Two surprising TYPO3 Performance Tips for Extension Developers

I recently did a performance analysis of a TYPO3 installation. Just from looking at the code it could not spot any major performance problems so I dug out the big guns and had a look at the code with xhprof.

As a five year TYPO3 extension developer who has seen quite a few things I was really surprised to find two significant things that I have not known about before.

1. Use PaginateViewHelper with caution

Fluid has a little known secret:

When using Fluid's PaginateViewHelper the template won't be cached.

More specifically: If a template contains a ViewHelper that implements the Facets\ChildNodeAccessInterface, but not the Facets\CompilableInterface it will not be cached, but recompiled on every call.

In TYPO3 6.2 these ViewHelpers are affected

  • f:widget.paginate

  • f:widget.autocomplete

  • f:be.menus.actionMenu

As Fluid Parsing is terribly slow without caching, we are talking on a timescale of seconds here even for simple templates.

Not using those ViewHelpers is probably not an option, but you can try keeping the templates that contain these as short as possible. Using partials helps a lot here:

EXT:my_extension/Resources/Private/Templates/list.html
<f:widget.paginate objects="{posts}" as="paginatedPosts">
  <f:for each="{paginatedPosts}" as="post">
    <f:render partial="Post/ListItem" arguments="{post:post}" />
  </f:for>
</f:widget.paginate>
EXT:my_extension/Resources/Private/Partials/post/list.html
<div class="post">
  <h1>{post.title}</h1>
  <p>{post.content}</p>
  <!-- other complex stuff -->
</div>

By just refactoring the Fluid templates with that in mind, we could speed up the rendering of a list view by 22% and save an additional 10MB of RAM per request.

If you want to dig deeper into the issue (or you just don't believe me ;) ), have a look at Fluid's TemplateParser. Ideally the parse()method should not be called on production (except on an empty cache). If you have some profiler running, check that this method is not causing you trouble. The code that disables the cache is in initializeViewHelperAndAddItToStack(), more specifically when setting

$state->setCompilable(FALSE);

2. Utilize the autoloader

It might sound insignificant, but you really should make sure to use the autoloader. In one project we could improve the frontend speed by almost 5% by teaching a legacy extension to use the autoloader.

Most legacy code has something like this in their code

1
2
3
$TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'][$_EXTKEY] = 
  'EXT:my_extension/path/to/file.php:tx_myextension_fooclass'
;

As long as this string is only parsed once this is nothing you need to worry about, but do it a few hundred or even a thousand times in one request and you are in trouble. When parsing the path and class name most time is spend in GeneralUtility::getFileAbsFileName. The extension key needs to be separated from the rest of the path, it must be checked if such an extension is enabled, and the path to the file needs to be determined. Ugh... lots of work... only to find out that the file was already included.

In the above code example the "getRecordOverlay" hook is used that is basically called everytime a record is fetched from the database. Depending on the complexity of the page this might be easily called a few hundred or thousand times while rendering a frontend page.

When using TYPO3's autoloader functionality the autoloader will only kick in the first time a class is required. Successive calls won't have any negative performance impact at all. And as a bonus you get code that is cleaner and easier to read.

Summary

There are lots of things one can do wrong when writing code. Most of those things don't have a measurable impact on performance, but some might turn out critical.

What are your tips to improve performance of TYPO3 Extensions?

2 Comments

Respond to this post

Claus Due wrote

Thanks for spreading the word about these! Especially the Fluid ViewHelper ChildNodeAccessorInterface issue is one to be aware of. It should also be noted that f:switch is among those ViewHelpers implementing ChildNodeAccessorInterface but not CompilableInterface: https://git.typo3.org/Packages/TYPO3.CMS.git/blob_plain/HEAD:/typo3/sysext/fluid/Classes/ViewHelpers/SwitchViewHelper.php

A while ago I wrote a feature into the "builder" extension which lets you scan all your template files for presences of any ViewHelper which cannot be cached - it doesn't identify *which* ViewHelper it is, but it is a very fast method of finding this specific type of bottleneck.

http://typo3.org/extensions/repository/view/builder

2014-09-19 16:25
Christian Weiske wrote

The fluid switch viewhelper (<f:switch>) also does not implement the CompilableInterface. Using <f:if> is much faster currently.

2015-01-23 11:39