Make WordPress Core

Opened 9 years ago

Closed 9 years ago

Last modified 7 years ago

#33898 closed enhancement (fixed)

Reduce Customizer peak memory usage by JSON-encoding settings and controls separately

Reported by: westonruter's profile westonruter Owned by: westonruter's profile westonruter
Milestone: 4.4 Priority: normal
Severity: normal Version: 3.4
Component: Customize Keywords: has-patch
Focuses: performance Cc:

Description

In working on a site with a lot of settings and controls in the Customizer, I found that peak memory usage (via memory_get_peak_usage()) can skyrocket, even to the point where memory usage would come up against the memory_limit and cause a fatal error. In investigating why, I found the culprit to be this line in wp-admin/customize.php:

var _wpCustomizeSettings = <?php echo wp_json_encode( $settings ); ?>;

Given a site that has 100 instances of a given widget that has 500 fields in it (see example widget code), the metrics are:

  • Initial _wpCustomizeSettings JSON size: 14,315,157 bytes
  • memory_get_usage(): 18,812,904
  • memory_get_peak_usage(): 47,674,256

If, however, all settings and controls are looped over and serialized separately, these are the metrics:

  • Initial _wpCustomizeSettings JSON size: 6,803 bytes
  • memory_get_usage(): 18,812,904
  • memory_get_peak_usage(): 19,980,976

In both cases, the PHP render time was 0.5 seconds, so doing multiple wp_json_encode() calls does not add significant processing time compared with a single wp_json_encode(). The improvements to memory are dramatic, however. But when serializing all of the data together, the peak memory usage is 140% larger (2.4× higher) than when the settings and controls get serialized individually.

In other words, by serializing settings and controls individually, we can cut peak memory usage more and less in half, depending on how many settings and controls are registered the Customizer.

Attachments (5)

33898.diff (3.2 KB) - added by westonruter 9 years ago.
https://github.com/xwp/wordpress-develop/pull/121
33898.2.diff (18.8 KB) - added by westonruter 9 years ago.
Additional changes: https://github.com/xwp/wordpress-develop/compare/9591c75...a9126f3
33898.3.diff (19.0 KB) - added by westonruter 9 years ago.
Additional change: https://github.com/xwp/wordpress-develop/commit/9e719a39a76386906800110b4393403f7f66adfb
33898.4.diff (25.7 KB) - added by westonruter 9 years ago.
https://github.com/xwp/wordpress-develop/pull/121/files#diff-7ab28a2bee855d3893686a7a245b8440
class-wp-customize-manager.php.diff (745 bytes) - added by westonruter 9 years ago.
PhpDoc fixes (though I don't see any missing return tags)

Download all attachments as: .zip

Change History (19)

#1 @westonruter
9 years ago

  • Keywords has-patch added

33898.diff implements the change. I piloted this change in a feature plugin as well: https://github.com/xwp/wp-customize-widgets-plus/pull/32/files

#2 @westonruter
9 years ago

I want to take this opportunity to move the logic that is currently in customize.php into a method on WP_Customize_Manager, in the same way that has already been done for the preview with WP_Customize_Manager::customize_preview_settings().

This ticket was mentioned in Slack in #core by westonruter. View the logs.


9 years ago

#4 @westonruter
9 years ago

  • Keywords needs-unit-tests added

In 33898.2.diff:

Serialize settings individually in Preview to avoid memory peak spike.

Move logic from customize.php to WP_Customize_Manager class.

  • Move logic for exporting JS to Customizer pane to customize_pane_settings() method, to correspond to customize_preview_settings().
  • Move logic for setting preview url, return url, and autofocus
  • Move iOS detection to helper method.
  • Create get_document_title_template method instead of global variable.
  • Use wp_json_encode() for outputting ajaxurl.
  • Move rendering of templates and outputting of settings to customize_controls_print_footer_scripts action.

What's remaining are unit tests for these new methods, the logic for which was previously not testable since it was inline to the customize.php template code.

This ticket was mentioned in Slack in #core-customize by westonruter. View the logs.


9 years ago

#6 @valendesigns
9 years ago

I've tested 33898.3.diff and it does provide some compelling server performance gains. Here are my numbers.

Before patch and widgets were added.

memory_get_peak_usage(): 45,144,424
memory_get_usage(): 43,918,288
page render time: 1442447924.82

After 100 heavy widgets were added.

memory_get_peak_usage(): 89,830,720
memory_get_usage(): 57,363,952
page render time: 1442447321.09

After the patch was applied. However, I did not save any data to the widgets so the gains were not as dramatic but still very good!

memory_get_peak_usage(): 57,615,968
memory_get_usage(): 56,713,744
page render time: 1442447292.99

#7 @westonruter
9 years ago

(The page render times above are from some invalid debugging code I provided.)

#8 @westonruter
9 years ago

  • Keywords commit added; needs-unit-tests removed

#9 @westonruter
9 years ago

  • Owner set to westonruter
  • Resolution set to fixed
  • Status changed from new to closed

In 34269:

Customize: Reduce peak memory usage by JSON-encoding settings and controls individually.

When there are hundreds of settings and controls (e.g. nav menu items and widget instances) the resulting object that is JSON-encoded can become very large, and wp_json_encode() can consume a lot of memory to serialize it. By breaking down the serialization into multiple calls the peak memory usage can be kept in line.

Moves logic out of wp-admin/customize.php into the WP_Customize_Manager class with new methods:

  • is_ios()
  • get_document_title_template()
  • get_preview_url()/set_preview_url()
  • get_return_url()/set_return_url()
  • get_autofocus()/set_autofocus()
  • customize_pane_settings()

Includes unit tests for these methods, for which the logic was formerly untestable in customize.php.

Fixes #33898.

#10 @DrewAPicture
9 years ago

  • Keywords commit removed
  • Resolution fixed deleted
  • Status changed from closed to reopened

Really nice job on the docs for these new methods and properties! Unfortunately, reopening because it looks like a few return descriptions got missed.

@westonruter
9 years ago

PhpDoc fixes (though I don't see any missing return tags)

#11 @westonruter
9 years ago

  • Resolution set to fixed
  • Status changed from reopened to closed

In 34320:

Customize: Flesh out phpdoc for WP_Customize_Manager.

  • Add missing phpdoc for class member variables.
  • Supply missing @return descriptions from [34269].
  • Add missing @since tags.
  • Remove unused $customized protected class member variable.

Fixes #33898.

This ticket was mentioned in Slack in #core by westonruter. View the logs.


9 years ago

This ticket was mentioned in Slack in #core-restapi by westonruter. View the logs.


8 years ago

#14 @johnbillion
7 years ago

In 40521:

Build/Test Tools: Remove a useless test.

See #33898, #40533

Note: See TracTickets for help on using tickets.