Smarty 5.5.1 significantly slower than 4.5.5
Hi wisskid, hi smarty community, we are about to update our smarty version from 4.5.5 to 5.5.1. We wrote some unit tests and realized that the new version runs significantly slower than the old version. For example the following code needs 3.134 s with v4.5.5 and 3.976 s with v5.5.1:
for ($i = 0; $i < 200000; ++$i) {
$smartyTemplate = 'string:{assign var=title value="some title"}
{$title|lower}';
$result = $this->fixture->fetch($smartyTemplate);
$this->assertEquals('some title', trim($result));
}
I also tried it out with a registered php function:
for ($i = 0; $i < 200000; ++$i) {
$smartyTemplate = 'string:{assign var=title value="some title"}
{$title|urlencode}';
$result = $this->fixture->fetch($smartyTemplate);
$this->assertEquals('some+title', trim($result));
}
I could increase the speed and get it close to version 4 by calling the generated template function directly like:
/**
* @throws \Smarty\Exception
*/
public function testUrlEncode(): void
{
for ($i = 0; $i < 100000; ++$i) {
$smartyTemplate = 'string:{assign var=title value="some title"}
{$title|urlencode}';
$template = $this->fixture->createTemplate($smartyTemplate);
ob_start();
$this->content_68433e5d15ee35_72556349($template);
ob_end_clean();
$result = ob_get_clean();
$this->assertEquals('some+title', trim($result));
}
}
function content_68433e5d15ee35_72556349 (\Smarty\Template $_smarty_tpl)
{
$_smarty_current_dir = '.';
$_smarty_tpl->assign('title', "some title", false, NULL);
echo $_smarty_tpl->getSmarty()->getModifierCallback('urlencode')($_smarty_tpl->getValue('title'));
}
We also did bigger tests with a template which included more than 100 registered php functions running in a 100000x loop. This resulted in 3.368 s vs 10.748 s. But I think the easier template above already shows the difference sufficently.
To me it looks like there is a bigger performance overhead in the smarty 5 classes. Did you do some performance tests during development of the new major version? Can you confirm that smarty 5 is significantly slower? Are there some options or tricks to bring the performance close to verson 4?
I think you did a very specific comparison (not intentionally, I'm sure) where Smarty 5 is a bit less fast. Smarty 5 runs ucfirst through an extension instead of compiling it into native php function call. In real life scenarios it should in fact perform significantly faster than v4.
Have a look at https://github.com/smarty-php/smarty-vs-twig-benchmark and compare this with https://github.com/AliShareei/smarty-vs-twig-benchmark
Thank you for the response, @wisskid .
The mentioned benchmarks don't contain any functions or function modifiers. In that way they are missing an important part in their performance evaluation. At least according to what we look at. And certainly they were executed at different times on different systems, so the timespans for the smarty versions are not really comparable in my opinion.
Nevertheless I executed the exact benchmarks one after the other on our dev server. The result:
v4.5.5 for 100.000 iterations: Time taken: 5.3401870727539 Time taken per iteration: 5.3401870727539E-5
v5.5.1 for 100.000x: Time taken: 6.9569668769836 Time taken per iteration: 6.9569668769836E-5
I can't help it. Smarty 5 seems to be some quite amount slower. Could you please verify this on your own?
What do you mean by Smarty 5 runs ucfirst?
What do you mean by Smarty 5 runs ucfirst?
Sorry, typo, I meant urlencode. Where Smarty v4 simply compiles any PHP callable to a native PHP call, Smarty v5 uses an Extension system. That may add (a tiny bit) of overhead, but adds a ton of security and other benefits.
If you have to, you can write a modifier compiler which compiles urlencode into native PHP code again and get the same compiled code. But I doubt you will ever need that.
Could you please verify this on your own?
When I adapt https://github.com/smarty-php/smarty-vs-twig-benchmark to run with Smarty v4 and try 1.000.000 iterations with smarty_reuse (which is a fairer comparison) it crashes with out of memory on my machine. The Smarty v5 version runs fine. I managed to run it at 10.000 iterations. At this amount of iterations smarty v4 runs in 0.86 seconds and Smarty v5 at 0.09.
I think what you should take away from this is that the overhead of Smarty is extremely low when compared to the time spent in actual application code.
If I use the parameter reuse I'am indeed faster. It's because the reuse of smarty 4 is someow slower than without reuse. Is it the same at your machine?
smarty4 100000: 5.3507568836212
smarty4_reuse 100000: 13.073413848877
smarty5 100000: 6.9542438983917
smarty5_reuse 100000: 6.7165148258209
twig3 100000: 4.0626268386841
twig3_reuse 100000: 3.6542191505432
smarty4 10000: 0.52665615081787
smarty4_reuse 10000: 1.2963349819183
smarty5 10000: 0.69982504844666
smarty5_reuse 10000: 0.65918803215027
twig3 10000: 0.4032039642334
twig3_reuse 10000: 0.36042213439941
We never used the reuse way in our code (propably lack of knowledge). We always give the template to the fetch method. And in this case the smarty benchmark (without php functions) is slower with Smarty5.
Our application uses smarty for converting data (not generating html websites). And therefore the templates are called repeatedly (like almost 500.000 times in the following example):
Smarty4:
..Convert: .....................ConvertTime: 1198.1795606613
..Convert: ...........ConvertTimePerProcAvg: 171.1685086659
..Convert: .............Products per Second: 402
// IMPORT STOP - Runtime: 0d 0h 25m 40s - Total: 481138 Success: 258984 Filtered: 209884 BWList: 18 Error: 12252
Smarty5:
..Convert: .....................ConvertTime: 1637.4283430576
..Convert: ...........ConvertTimePerProcAvg: 233.91833472252
..Convert: .............Products per Second: 294
// IMPORT STOP - Runtime: 0d 0h 33m 5s - Total: 481138 Success: 258984 Filtered: 209884 BWList: 18 Error: 12252
In that convert other processing takes place. Not just templates are being processed. But the running time decreases significantly for our customers. Maybe this describes our problem a bit better.
I will definately try out your proposal to change the compiled template code with modifiers.
Meanwhile can you give an update about the support of smarty 4. Will you still provide a fix if a security breach is found in smarty 4? An answer would help us adjusting our timeline more appropriately.
That is a very interesting (and specific) workload indeed. Possibly, taking a look at the compiled templates and comparing them to their v4 equivalents can shed some light on this.
And, switching to v5 with reuse might improve your runtime.
And yes, Smarty 4 still has security support. There are no plans to drop that anytime soon.