Fluid - Static PHP Caching

by Sebastian Kurfürst on 12.07.2011

On last Sunday, Bastian has arrived in Dresden for a code sprint to implement compilation of Fluid Templates to PHP code. This post explains first how we worked, and then shows what matters most: Results 

The Workflow

On the first evening, we mainly worked on setting up the environment and create a reliable profiling environment – next to spending a nice evening in Dresden, of course. 

On Monday morning, we used our newly created benchmark framework and did some baseline measurements, which you see below. Our performance measurement microframework is based on XHProf, and implements a little GUI on top of XHProf which can be used to see different runs and optimizations on a single glance.

We mainly tested the following setups:

  • many objects
  • many forms
  • high nesting level
  • many partials

After the baseline measurements, we started with implementing the compilation phase — and after a few hours, we were successful in rendering our first compiled template! After that, we were able to work iteratively: Checking why a particular rendering is slow, identifying the bottle necks, and testing if our improvements helped.


Numbers count most, and that’s why we want to share them with you. All numbers have been measured on my MacBook Pro 2.4 GHz Intel Core 2 Duo, with 4 GB RAM and a normal hard disk. Feel invited to test Fluid for yourself, making your own benchmarks.

The columns of the result table mean the following:

  • Instanciations: Number of object creations
  • Runtime: complete rendering time in seconds
  • Memory: Maximum taken memory in MB

The rows mean the following:

  • Before: before the optimization
  • BuildCache: this is the first run, when the template is not yet cached; and a cached representation is built.
  • Cached: all other runs after the first run are served from the cached template.

500 Objects

Testing setup: <f:for> loop over 500 objects.

Instanciations Runtime Memory
Before 2 165 0.59 1.15
BuildCache 149 0.42 1.9
Cached 73 0.12 0.8

5000 Objects

Testing setup: <f:for> loop over 5000 objects.

Instanciations Runtime Memory
Before 20 165 5.6 1.46
BuildCache 149 3.8 1.65
Cached 73 1.15 1.07

recursive list – nesting level 6

Testing setup: seven nested <f:for> loops, yielding around 5 500 object accesses

Instanciations Runtime Memory
Before 13 987 3.76 1.98
BuildCache 247 2.76 2.17
Cached 73 0.80 1.05

recursive list – nesting level 7

Testing setup: seven nested <f:for> loops, yielding around 22 000 object accesses

Instanciations Runtime Memory
Before 54 986 15.25 4.01
BuildCache 268 11.62 4.21
Cached 73 3.24 2.25

1000 partials

Testing setup: rendering a single partial 1000 times

Instanciations Runtime Memory
Before 26 157 3.11 9.95
BuildCache 2 168 0.76 2.5
Cached 2 081 0.63 1.15

Improving Performance Based On Clean Design

The above performance improvements are absolutely transparent to the developer or the template designer; everybody using Fluid will benefit from these improvements.

Well, that’s not 100% true: We have one single change which is not backwards-compatible; however this change was not even in the public API, and we believe that the performance improvements are absolutely worth it!

We designed Fluid in a clean and object-oriented way — mainly using an object-based syntax tree for internal representation of a template. This enables performance optimizations as we did now; without changing the public API or the behavior of the parser.

This shows very nicely that performance optimizations based on a clean architecture and design are perfectly possible – and we’ll definitely do such a performance code sprint for FLOW3 at some point.

Closing Notes

Pair Programming in Dresden with Bastian was awesome — and at some point, we will definitely repeat it. Aside to programming, we also spent a nice time in Dresden, went climbing in the Saxon Swizerland, relaxing, discussing and having fun.

The whole optimization work has been financed by AOE Media, so we’d like to thank them very much for their generosity and support! I cannot express in words how much your sponsoring helped. It really made these optimizations possible.

I also hope that some other agencies follow your lead, financing other core developers when they need improvements on various parts of the core.

Thanks for Reading