Skip to content

Commit eb8232b

Browse files
committed
Benchmark large template parsing performance
Current results for parsing the large template 1000 times: - JIT off: 191 seconds (191 ms/parse) - JIT on: 90 seconds (90 ms/parse)
1 parent f49cee0 commit eb8232b

5 files changed

Lines changed: 354 additions & 22 deletions

File tree

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"friendsofphp/php-cs-fixer": "^3.94",
2424
"ircmaxell/php-yacc": "dev-master",
2525
"jbboehr/handlebars-spec": "dev-master",
26-
"phpstan/phpstan": "^2.1.38",
26+
"phpstan/phpstan": "^2.1.40",
2727
"phpunit/phpunit": "^11.5"
2828
},
2929
"autoload": {

composer.lock

Lines changed: 17 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/ParserAbstract.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -601,12 +601,12 @@ protected function preparePath(bool $data, ?SubExpression $sexpr, array $parts,
601601
$tail = [];
602602
$depth = 0;
603603

604-
for ($i = 0; $i < count($parts); $i++) {
605-
$part = $parts[$i]->part;
604+
foreach ($parts as $segment) {
605+
$part = $segment->part;
606606
// If we have [] syntax then we do not treat path references as operators,
607607
// i.e. foo.[this] resolves to approximately context.foo['this']
608-
$isLiteral = $parts[$i]->original !== $part;
609-
$separator = $parts[$i]->separator;
608+
$isLiteral = $segment->original !== $part;
609+
$separator = $segment->separator;
610610

611611
$partPrefix = $separator === '.#' ? '#' : '';
612612

tests/benchmark.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
/**
4+
* Parser benchmark script. Default iterations: 1000.
5+
*
6+
* Usage: php -d opcache.enable_cli=1 -d opcache.jit=tracing tests/benchmark.php
7+
*/
8+
9+
use DevTheorem\HandlebarsParser\ParserFactory;
10+
11+
require __DIR__ . '/../vendor/autoload.php';
12+
13+
$iterations = (int) ($argv[1] ?? 1000);
14+
$filename = __DIR__ . "/largeTemplate.hbs";
15+
16+
// A large, complex template exercising as many syntax features as possible.
17+
$template = file_get_contents($filename);
18+
if ($template === false) {
19+
exit("Failed to open $filename");
20+
}
21+
22+
$parser = (new ParserFactory())->create();
23+
24+
// Warm up: give the JIT a chance to compile hot paths before we measure.
25+
for ($i = 0; $i < 50; $i++) {
26+
$parser->parse($template);
27+
}
28+
29+
$start = hrtime(true);
30+
31+
for ($i = 0; $i < $iterations; $i++) {
32+
$parser->parse($template);
33+
}
34+
35+
$elapsed = (hrtime(true) - $start) / 1e9;
36+
$perParse = $elapsed / $iterations * 1000;
37+
$templateBytes = strlen($template);
38+
39+
printf(
40+
"Parsed %d times in %.3f s | %.3f ms/parse | %.1f KB template\n",
41+
$iterations,
42+
$elapsed,
43+
$perParse,
44+
$templateBytes / 1024,
45+
);

0 commit comments

Comments
 (0)