Skip to content

Conversation

ilovepi
Copy link
Contributor

@ilovepi ilovepi commented Sep 22, 2025

The mustache library still has many issues with performance. While not
critical, template rendering is fairly simple, and should be fast. This
is hard to reason about without a benchmark. Since there is no standard
benchmark suite for Mustache, we can construct some benchmarks that will
stress our implementation.

This commit adds a new benchmark suite (MustacheBench) that tests several
key performance areas:

  • Parsing (Complex): Measures the one-time parse cost of a large
    template.
  • Parsing (Small): Measures the parse cost of a small template with deep
    keys.
  • Data Traversal: Stresses hot, cached data traversal using a
    5k-iteration loop inside the template.
  • Context Stack: Tests the render cost of deeply nested sections
    (50 levels).
  • Array Iteration: Benchmarks section iteration over a 100,000-item
    array.
  • Partial Rendering: Tests partial tag performance inside a large loop.
  • String Escaping: Measures HTML-escaping a large string.
  • String Unescaped (Triple): Baseline for {{{...}}} syntax.
  • String Unescaped (Ampersand): Baseline for {{& ...}} syntax.
  • Output Buffer: Tests rendering a single 1MB string.

Initial results show that Partial rendering is by far the slowest
operation. The cost per-item is ~3x higher than simple iteration,
because partial templates are being re-parsed on every call instead of
being cached. It also shows that the logic for HTML escaping is very
expensive likely due to the character by character parsing done to
escapes.

Copy link
Contributor Author

ilovepi commented Sep 22, 2025

This stack of pull requests is managed by Graphite. Learn more about stacking.

Copy link

github-actions bot commented Sep 22, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks ok, though I'm not familiar enough with mustache to know if benchmarking these things in particular makes sense.

@ilovepi ilovepi force-pushed the users/ilovepi/mustache-bench branch 3 times, most recently from 4404c23 to 0683179 Compare September 25, 2025 22:17
Copy link
Contributor Author

ilovepi commented Sep 25, 2025

Merge activity

  • Sep 25, 10:18 PM UTC: Graphite rebased this pull request as part of a merge.
  • Sep 25, 10:24 PM UTC: Graphite rebased this pull request as part of a merge.
  • Sep 25, 10:27 PM UTC: Graphite rebased this pull request as part of a merge.
  • Sep 25, 10:36 PM UTC: Graphite rebased this pull request as part of a merge.
  • Sep 25, 10:40 PM UTC: Graphite rebased this pull request as part of a merge.
  • Sep 25, 10:45 PM UTC: Graphite rebased this pull request as part of a merge.
  • Sep 25, 10:56 PM UTC: Graphite rebased this pull request as part of a merge.
  • Sep 25, 11:03 PM UTC: Graphite rebased this pull request as part of a merge.
  • Sep 25, 11:17 PM UTC: Graphite rebased this pull request as part of a merge.
  • Sep 25, 11:22 PM UTC: Graphite rebased this pull request as part of a merge.
  • Sep 25, 11:26 PM UTC: Graphite rebased this pull request as part of a merge.
  • Sep 25, 11:33 PM UTC: Graphite rebased this pull request as part of a merge.
  • Sep 25, 11:36 PM UTC: Graphite rebased this pull request as part of a merge.
  • Sep 25, 11:54 PM UTC: Graphite couldn't merge this PR because it was not satisfying all requirements (Failed CI: 'Build and Test Linux').

@ilovepi ilovepi force-pushed the users/ilovepi/mustache-bench branch 10 times, most recently from 686efa6 to e8a973d Compare September 25, 2025 23:25
@ilovepi ilovepi closed this Sep 25, 2025
@ilovepi ilovepi reopened this Sep 25, 2025
@ilovepi ilovepi enabled auto-merge (squash) September 25, 2025 23:29
@ilovepi ilovepi force-pushed the users/ilovepi/mustache-bench branch from e8a973d to 2d7f1b9 Compare September 25, 2025 23:33
The mustache library still has many issues with performance. While not
critical, template rendering is fairly simple, and should be fast. This
is hard to reason about without a benchmark. Since there is no standard
benchmark suite for Mustache, we can construct some benchmarks that will
stress our implementation.

This commit adds a new benchmark suite (MustacheBench) that tests several
key performance areas:

- Parsing (Complex): Measures the one-time parse cost of a large
  template.
- Parsing (Small): Measures the parse cost of a small template with deep
  keys.
- Data Traversal: Stresses hot, cached data traversal using a
  5k-iteration loop inside the template.
- Context Stack: Tests the render cost of deeply nested sections
  (50 levels).
- Array Iteration: Benchmarks section iteration over a 100,000-item
  array.
- Partial Rendering: Tests partial tag performance inside a large loop.
- String Escaping: Measures HTML-escaping a large string.
- String Unescaped (Triple): Baseline for {{{...}}} syntax.
- String Unescaped (Ampersand): Baseline for {{& ...}} syntax.
- Output Buffer: Tests rendering a single 1MB string.

Initial results show that Partial rendering is by far the slowest
operation. The cost per-item is ~3x higher than simple iteration,
because partial templates are being re-parsed on every call instead of
being cached. It also shows that the logic for HTML escaping is very
expensive likely due to the character by character parsing done to
escapes.
@ilovepi ilovepi force-pushed the users/ilovepi/mustache-bench branch from 2d7f1b9 to 47a5f24 Compare September 25, 2025 23:36
@ilovepi ilovepi disabled auto-merge September 26, 2025 00:08
@ilovepi ilovepi merged commit 1867ca7 into main Sep 26, 2025
8 of 9 checks passed
@ilovepi ilovepi deleted the users/ilovepi/mustache-bench branch September 26, 2025 00:09
@ilovepi
Copy link
Contributor Author

ilovepi commented Sep 26, 2025

Note the premerge failure was due to an existing lldb test failure, and unrelated to this patch.

@llvm-ci
Copy link
Collaborator

llvm-ci commented Sep 26, 2025

LLVM Buildbot has detected a new failure on builder clang-m68k-linux-cross running on suse-gary-m68k-cross while building llvm at step 5 "ninja check 1".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/27/builds/16618

Here is the relevant piece of the build log for the reference
Step 5 (ninja check 1) failure: stage 1 checked (failure)
...
[307/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/CXXMethodDecl.cpp.o
[308/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/QualTypeNamesTest.cpp.o
[309/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/ImplicitCtor.cpp.o
[310/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/ImplicitCtorInitializer.cpp.o
[311/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/AST/SourceLocationTest.cpp.o
[312/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/InitListExprPreOrder.cpp.o
[313/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/InitListExprPreOrderNoQueue.cpp.o
[314/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/DependencyScanning/DependencyScannerTest.cpp.o
[315/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RewriterTest.cpp.o
[316/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/AST/ASTImporterTest.cpp.o
FAILED: tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/AST/ASTImporterTest.cpp.o 
/usr/bin/c++ -DGTEST_HAS_RTTI=0 -DLLVM_BUILD_STATIC -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CXX11_ABI=1 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/tools/clang/unittests -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/unittests -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/tools/clang/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/unittests/Tooling -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/third-party/unittest/googletest/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/third-party/unittest/googlemock/include -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wno-missing-field-initializers -pedantic -Wno-long-long -Wimplicit-fallthrough -Wno-uninitialized -Wno-nonnull -Wno-class-memaccess -Wno-dangling-reference -Wno-redundant-move -Wno-pessimizing-move -Wno-array-bounds -Wno-stringop-overread -Wno-noexcept-type -Wdelete-non-virtual-dtor -Wsuggest-override -Wno-comment -Wno-misleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual -O3 -DNDEBUG -std=c++17  -Wno-variadic-macros -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -Wno-suggest-override -MD -MT tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/AST/ASTImporterTest.cpp.o -MF tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/AST/ASTImporterTest.cpp.o.d -o tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/AST/ASTImporterTest.cpp.o -c /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/unittests/AST/ASTImporterTest.cpp
c++: fatal error: Killed signal terminated program cc1plus
compilation terminated.
[317/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/LambdaTemplateParams.cpp.o
[318/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/IntegerLiteral.cpp.o
[319/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/NestedNameSpecifiers.cpp.o
[320/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/TraversalScope.cpp.o
[321/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/ParenExpr.cpp.o
[322/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp.o
[323/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp.o
[324/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RangeSelectorTest.cpp.o
[325/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/LambdaDefaultCapture.cpp.o
[326/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp.o
[327/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/ASTMatchers/ASTMatchersNodeTest.cpp.o
[328/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/Attr.cpp.o
[329/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp.o
[330/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/MemberPointerTypeLoc.cpp.o
[331/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/InitListExprPostOrderNoQueue.cpp.o
[332/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/TemplateArgumentLocTraverser.cpp.o
[333/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/InitListExprPostOrder.cpp.o
[334/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/ReplacementsYamlTest.cpp.o
[335/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RefactoringActionRulesTest.cpp.o
[336/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/ASTMatchers/ASTMatchersNarrowingTest.cpp.o
[337/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RefactoringTest.cpp.o
[338/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RefactoringCallbacksTest.cpp.o
[339/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTestPostOrderVisitor.cpp.o
[340/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/SourceCodeBuildersTest.cpp.o
[341/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/CallbacksBinaryOperator.cpp.o
[342/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/ToolingTest.cpp.o
[343/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/CallbacksUnaryOperator.cpp.o
[344/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/CallbacksCompoundAssignOperator.cpp.o
[345/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/CallbacksCallExpr.cpp.o
[346/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/SourceCodeTest.cpp.o
[347/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/RecursiveASTVisitorTests/CallbacksLeaf.cpp.o
[348/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Tooling/StencilTest.cpp.o
[349/1193] Building CXX object tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/ASTMatchers/ASTMatchersTraversalTest.cpp.o
ninja: build stopped: subcommand failed.

mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Oct 3, 2025
The mustache library still has many issues with performance. While not
critical, template rendering is fairly simple, and should be fast. This
is hard to reason about without a benchmark. Since there is no standard
benchmark suite for Mustache, we can construct some benchmarks that will
stress our implementation.

This commit adds a new benchmark suite (MustacheBench) that tests
several
key performance areas:

- Parsing (Complex): Measures the one-time parse cost of a large
  template.
- Parsing (Small): Measures the parse cost of a small template with deep
  keys.
- Data Traversal: Stresses hot, cached data traversal using a
  5k-iteration loop inside the template.
- Context Stack: Tests the render cost of deeply nested sections
  (50 levels).
- Array Iteration: Benchmarks section iteration over a 100,000-item
  array.
- Partial Rendering: Tests partial tag performance inside a large loop.
- String Escaping: Measures HTML-escaping a large string.
- String Unescaped (Triple): Baseline for {{{...}}} syntax.
- String Unescaped (Ampersand): Baseline for {{& ...}} syntax.
- Output Buffer: Tests rendering a single 1MB string.

Initial results show that Partial rendering is by far the slowest
operation. The cost per-item is ~3x higher than simple iteration,
because partial templates are being re-parsed on every call instead of
being cached. It also shows that the logic for HTML escaping is very
expensive likely due to the character by character parsing done to
escapes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants