The third and final article will provide practical solutions for optimizing performance.
If your actual performance (from your benchmarking tests) does not meet your requirements, you should finetune your eZ Publish installation. Recall the different components of page load time, such as page generation and transfer time. Here, we will take a look at how you can identify the causes of slow website performance, focusing on eZ Publish settings that affect page generation times.
Debug output is a built-in mechanism in eZ Publish that provides detailed information for troubleshooting. Debug output provides valuable information about timings, SQL queries, template processing and more. You can enable debug output from within the Administration Interface (in the Common INI settings in the Setup tab) or by adding the following line in your site.ini.append.php file:
[DebugSettings] DebugOutput=enabled
This section displays errors, warnings, notices and other important information from the eZ Publish kernel, modules, extensions and so on. This section also displays SQL queries when SQLOutput is enabled. Debug settings such as SQLOutput are described later in this article.
This section displays timings and the amount of memory spent on processing modules or template blocks. PHP must be compiled with the --enable-memory-limit option in order to be able to show the amount of used memory. This section also displays timing points and accumulated time in your templates. These functions are described below, and are used to test the performance of your template code.
You can manually add timing points to eZ Publish templates. This is useful to see how much time specific parts of complex templates take to process.
The example below demonstrates how the debug-timing-point mechanism can be used to measure the time it takes to fetch and print the names of all nodes that are below node number 2.
{debug-timing-point id='test'} {def $nodes=fetch( 'content', 'tree', hash( 'parent_node_id', 2 ) )} {foreach( $nodes as $node )} {$node.name|wash()} {/foreach} {/debug-timing-point}
Here is the sample debug ouput for the timing points:
The timing points section of debug output
One thing to note here is that the last and second-to-last times in the timing points are usually different. The second-to-last point, labelled "End", shows the total processing time. The "Total runtime" also includes the flushing of the output buffer, which means that the content has been sent to the browser. If you have a slow connection, there will be a larger difference between these numbers.
When you are developing eZ Publish extensions in PHP, you often need to find how much time the different parts of your code take to process. Timing points can be added with the method addTimingPoint in the eZDebug class. This enables you to track different parts in the code and display the time spent between the different points in the debug output.
PHP code example:
eZDebug::addTimingPoint( "My module start processing" ); ... ... eZDebug::addTimingPoint( "My module end processing" );
This section of the debug output displays timing information about various parts of the system, such as template processing, character set conversions, XML processing and information about SQL queries. This section also displays the results from the debug-accumulator template function.
If you have groups of tasks that span several templates and you want to measure the total time spent on the tasks, you can use the time accumulator functions. All time accumulated with the same ID is shown in the same summary in the debug output.
This example demonstrates how the debug-accumulator mechanism can be used to generate debug statistics based on the encapsulated template code.
{debug-accumulator id='test'} {def $nodes=fetch( 'content', 'tree', hash( 'parent_node_id', 2 ) )} {foreach( $nodes as $node )} {$node.name|wash()} {/foreach} {/debug-accumulator}
The time accumulators section of debug output
When you have repeating code in your extensions, you can add an accumulator to summarize the time spent on the specific code. The example below shows how you can add an accumulator around a MySQL string conversion. This will be summarized in the group mysql_total in the debug output with the label "String conversion in MySQL".
PHP code example:
eZDebug::accumulatorStart('mysql_conversion', 'mysql_total', 'String conversion in MySQL'); ... ... eZDebug::accumulatorStop('mysql_conversion');
eZ Publish's site.ini.append.php configuration file contains some useful debug settings to customize the debug output's behavior:
Note: Currently this only works for MySQL, and not other types of database such as Oracle.
The Administration Interface with ShowXHTMLCode and Debug enabled
When ShowXHTMLCode is set to disabled and Debug is enabled, the template names appear as XHTML comments, which can still be viewed in the page source code as shown below:
<!-- START: including template: design/standard/templates/page_head.tpl (design/standard/templates/page_head.tpl) -->
This section contains information on typical scenarios that can cause performance problems. We will describe how to spot and solve them.
When character sets are wrongly configured, eZ Publish will use charset conversion as shown in the picture below. This is not necessary and reduces performance:
An example time breakdown for charset conversion
The following example presents an incorrect charset configuration:
i18n.ini.append.php: [CharsetSettings] Charset=utf-8 template.ini.append.php [CharsetSettings] DefaultTemplateCharset=iso-8859-1
You can define character sets in three places: the database, internally and in templates. In this example, the databases and templates are using the latin1 charset, but the internal charset is set to Unicode. To remedy this problem, ensure that all the character sets used in eZ Publish are the same.
When template compilation is disabled, eZ Publish parses all templates "on the fly". This is helpful during development when you are testing template changes frequently, but it takes a lot of server resources and significantly reduces performance. A common mistake is to forget to enable template compilation when transitioning to a "live" site. The example debug output below shows the template processing times when compilation is disabled.
You can see that time is spent parsing the text and constructing the internal template execution tree before the template is actually processed. This is not necessary.
To fix this, simply enable template compilation:
site.ini.append.php: [TemplateSettings] TemplateCompile=enabled
Viewcache is the terminology we use for the cache that stores the complete HTML output of a view. This is similar to template compilation in that it avoids the complete regeneration of a view each time it is accessed. If a development site goes "live" with viewcaching disabled, this reduces performance and increases page load times. Live sites should always have viewcaching enabled.
Here is an example debug output when viewcache is disabled:
Example processing times with viewcache disabled
To fix this, simply enable viewcaching:
site.ini.append.php: [ContentSettings] ViewCaching=enabled
If eZ Publish is installed on a Linux/UNIX-based system, some of the file permissions need to be changed. The most common issue is that the webserver does not have write access to the settings/, design/ and var/ directories. In this case, eZ Publish will report an error as shown in the picture below:
eZ Publish is bundled with a script called modfix.sh that sets the correct permissions. The script needs to be run from within the eZ Publish base directory:
$ cd /path/to/ez_publish $ bin/modfix.sh
The modfix script recursively alters the permission settings of the following directories:
var/* settings/* design/*
You can also set these permissions manually. If you know the user and group of the webserver, it is recommended to use a different set of permissions. This is more secure, as it only allows write access for the webserver user and group.
$ chmod og+rwx -R var $ chown -R example:example var
The "example:example" notation must be changed to the user and group of the webserver.
The time spent accessing the database in eZ Publish is usually low (1-20% of the total page generation time, depending on how complex a given page is). If you disable viewcaching and look at the debug output, you can see how much time is spent on the database connection. Either the connection to the database or the database itself might be running slowly.
Here is some sample debug output on database timing:
Here is a slow SQL query (with SQLOutput enabled):
Redundant usage of the fetch function can produce a lot of unnecessary SQL queries. This reduces performance and wastes server resources. By using the debug output with disabled viewcaching, you can see how many SQL queries are performed. Below we present example template syntax used to fetch children and sub-children from a folder:
{foreach fetch(content, list,hash(parent_node_id, 2)) as $object} {def $sub_children=fetch( content, list, hash( parent_node_id, $object.node_id ) )} Child name: {$object.name}<br/> {foreach $sub_children as $sub_child} Sub-child name: {$sub_child.name}<br /> {/foreach} {/foreach}
This code produces a lot of unnecessary SQL queries and can be replaced with:
{foreach fetch(content, list,hash(parent_node_id, 2)) as $object} Child name: {$object.name}<br /> {foreach $object.children as $sub_child} Sub-child name: {$sub_child.name}<br /> {/foreach} {/foreach}
Here is an example debug output with a large number of SQL queries:
In this article, we have outlined the features of eZ Publish's debug output. Functions such as timing points and accumulators, along with a number of debug settings, can help to reveal problem areas related to site performance. We welcome your comments and tips regarding eZ Publish performance and debug settings.
In the final article in this three-part series, we will build on the benchmarking and debug output knowledge that you have gained to describe concrete solutions to improve your eZ Publish site's performance.