Benchmarking eZ: memory consumption for the webservice use case

Tuesday 01 March 2011 6:16:00 am

By : Gaetano Giunta

The amount of memory used by the application to render a single page is an important metric to be taken into account when sizing webservers to cope with the desired amount of traffic. In this installment, we explore memory usage by eZ Publish, in the context of a "webservice" page, ie. a page rendering a very simple piece of text in json format. We focus on an aspect outside control of the developer: php files with class definitions.

Sizing servers

The rule of thumb, for a server dedicated to running only Apache, is to start with the installed memory, take away a fixed amount for the OS (eg. 500MB) and divide the rest for the number of concurrent webservers processes expected. For a 4GB server, with 100 processes, that means 35MB per process.

Do remember that if a php page consumes eg. 30MB, and the following requested page only 10MB, Apache will not release to the OS the extra 20MB until the process that served the 1st page is recycled.

This is a good reason for keeping an eye on the MaxRequestperChild parameter to keep your processes refreshing now and then (but not once per minute, or you'll slow don everything in process creation and killing). It is also an excellent reason to install a separate web application for serving static content (eg. nginx), even on the same server, and for doing proper usage of the caches in your eZ Publish applications. It might also be a good idea to have the editorail siteaccess on a separate server, since "editing" pages tend to chew up momery memory than "display" pages.

Things outside of developer's control

Even with the most advanced cache-block technique in place, the number of php classes used by eZ Publish to do its job is outside of the control of the developer. And every parsed php file chews up some memory. What I set out to do here is to measure the minimum number of php files that are loaded by the system, their size on disk, and the memory consumed by php for loading them.

Measurement methodology

A stripped-down eZ Publish 4.5beta1 install was measured:

  • 2 siteaccess
  • english language content only
  • all default content classes and demo content removed
  • all extensions disabled (this means admin2 design cannot be used, as it relies on ezjscore)
  • template translation disabled
  • all ini files set up by the install wizard but not necessary for testing removed
  • homepage is from a content class with a single attribute (text line)

This in order to obtain the lowest possible memory usage.

The autoload.php file was then patched to record the php files loaded and the memory used by php before and after the inclusion. Total memory at the end of script execution was not measured.

All tests were done on windows 32bit, with php 5.3.5. No opcode cache in use.

Results

  • caches emptied in admin interface, 1st load of homepage (using the pagelayout and node template from the "base" design): 19,66 MB ram; 102 php files totaling 3,17MB on disk
  • same with caches primed: 10,22 MB ram; 51 php files totaling 1,69 MB on disk
  • same with a 'clean' pagelayout (ie. only containing module_result): 10,22 MB ram, 47 php files totaling 1,62 MB on disk
  • using a 'clean' pagelayout and a custom module (no content view) that only echoes current time without using a template: 8,91 MB ram, 46 php files totaling 1,37 MB on disk
  • using a jsonrpc service (with the ggwebservices extension) that echoes current time: 6,55 MB ram, 45 php files totaling 1,08MB on disk
  • using the new REST API layer and a json view displaying the current time: 4,45 MB ram, 90 php files

Conclusions

  • the biggest offenders in terms of size/memory used are the eZTemplateCompiler and eZContentObject php classes. If eZP could avoid loading them at all on a page with view caches fully on, almost 2MB of ram would be saved
  • many php classes are brought in even if only one or two of their methods are used. Eg. ezdebugsetting which is always pulled in even with debug off; ezphpcreator; the charset/codec layer
  • a lot of refactoring work would be needed to split off these classes into lighter "stubs". eg. the ezdebug class could be split in one light half-class that is always pulled in, and one heavy half class that is only pulled in when debug is in fact active (the debug-writer part)
  • using a module view that bypasses the template layer by calling eZExecution::cleanExit(); instead of using an empty pagelayout can result in some memory saving
  • the new controller layer implemented in the REST API does much better than what can be obtained via a custom module/view with the current API!
Powered by eZ Publish™ CMS Open Source Web Content Management. Copyright © 1999-2014 eZ Systems AS (except where otherwise noted). All rights reserved.

eZ debug

Timing: Jan 18 2025 10:40:28
Script start
Timing: Jan 18 2025 10:40:28
Module start 'layout'
Timing: Jan 18 2025 10:40:28
Module start 'content'
Timing: Jan 18 2025 10:40:28
Module end 'content'
Timing: Jan 18 2025 10:40:28
Script end

Main resources:

Total runtime0.1055 sec
Peak memory usage6,144.0000 KB
Database Queries39

Timing points:

CheckpointStart (sec)Duration (sec)Memory at start (KB)Memory used (KB)
Script start 0.00000.0063 589.5859152.6563
Module start 'layout' 0.00630.0028 742.242239.5313
Module start 'content' 0.00900.0952 781.7734374.1797
Module end 'content' 0.10430.0012 1,155.953114.3984
Script end 0.1055  1,170.3516 

Time accumulators:

 Accumulator Duration (sec) Duration (%) Count Average (sec)
Ini load
Load cache0.00302.8144150.0002
Check MTime0.00121.1758150.0001
Mysql Total
Database connection0.00100.907910.0010
Mysqli_queries0.044342.0084390.0011
Looping result0.00040.3606360.0000
Template Total0.066462.920.0332
Template load0.00201.939120.0010
Template processing0.064360.966620.0322
Template load and register function0.00010.088110.0001
states
state_id_array0.00201.905010.0020
state_identifier_array0.00121.102220.0006
Override
Cache load0.00161.5599390.0000
Sytem overhead
Fetch class attribute name0.00171.624320.0009
class_abstraction
Instantiating content class attribute0.00000.006820.0000
General
dbfile0.00060.5811100.0001
String conversion0.00000.007940.0000
Note: percentages do not add up to 100% because some accumulators overlap

Templates used to render the page:

UsageRequested templateTemplateTemplate loadedEditOverride
1node/view/full.tplblog_entry/full.tplextension/community_design/design/suncana/override/templates/blog_entry/full.tplEdit templateOverride template
2content/datatype/view/ezxmltext.tpl<No override>extension/community_design/design/suncana/templates/content/datatype/view/ezxmltext.tplEdit templateOverride template
5content/datatype/view/ezxmltags/header.tpl<No override>design/standard/templates/content/datatype/view/ezxmltags/header.tplEdit templateOverride template
5content/datatype/view/ezxmltags/paragraph.tpl<No override>extension/ezwebin/design/ezwebin/templates/content/datatype/view/ezxmltags/paragraph.tplEdit templateOverride template
3content/datatype/view/ezxmltags/li.tpl<No override>design/standard/templates/content/datatype/view/ezxmltags/li.tplEdit templateOverride template
3content/datatype/view/ezxmltags/ul.tpl<No override>design/standard/templates/content/datatype/view/ezxmltags/ul.tplEdit templateOverride template
1print_pagelayout.tpl<No override>extension/community/design/community/templates/print_pagelayout.tplEdit templateOverride template
 Number of times templates used: 20
 Number of unique templates used: 7

Time used to render debug report: 0.0001 secs