Skip to content

Fix Handlebars benchmarks #775

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions Fluid.Benchmarks/BaseBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;

namespace Fluid.Benchmarks
{
public abstract class BaseBenchmarks
{
protected List<Product> Products = new List<Product>(ProductCount);
protected List<Product> Products = new(ProductCount);

protected const int ProductCount = 500;
protected const int ProductCount = 100;

protected const string Lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum";

Expand Down Expand Up @@ -47,11 +48,23 @@ public BaseBenchmarks()
}
}

public void CheckBenchmark()
{
var result = ParseAndRender();
if (string.IsNullOrEmpty(result) ||
!result.Contains("<h2>Name0</h2>") ||
!result.Contains($"<h2>Name{ProductCount - 1}</h2>") ||
!result.Contains($"Lorem ipsum ...") ||
!result.Contains($"Only 0") ||
!result.Contains($"Only {ProductCount - 1}"))
{
throw new InvalidOperationException($"Template rendering failed: \n {result}");
}
}

public abstract object Parse();
public abstract object ParseBig();

public abstract string Render();

public abstract string ParseAndRender();

}
Expand Down
9 changes: 6 additions & 3 deletions Fluid.Benchmarks/ComparisonBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,19 +66,22 @@ public string DotLiquid_Render()
return _dotLiquidBenchmarks.Render();
}

[Benchmark, BenchmarkCategory("Parse")]
// Ignored since Liquid.NET is much slower and not in active development
[BenchmarkCategory("Parse")]
public object LiquidNet_Parse()
{
return _liquidNetBenchmarks.Parse();
}

[Benchmark, BenchmarkCategory("ParseBig")]
// Ignored since Liquid.NET is much slower and not in active development
[BenchmarkCategory("ParseBig")]
public object LiquidNet_ParseBig()
{
return _liquidNetBenchmarks.ParseBig();
}

[Benchmark, BenchmarkCategory("Render")]
// Ignored since Liquid.NET is much slower and not in active development
[BenchmarkCategory("Render")]
public string LiquidNet_Render()
{
return _liquidNetBenchmarks.Render();
Expand Down
4 changes: 3 additions & 1 deletion Fluid.Benchmarks/CompiledFluidBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;

namespace Fluid.Benchmarks
{
Expand All @@ -14,6 +14,8 @@ public CompiledFluidBenchmarks()
_options.MemberAccessStrategy.Register<Product>();
_options.MemberAccessStrategy.MemberNameStrategy = MemberNameStrategies.CamelCase;
_parser.TryParse(ProductTemplate, out _fluidTemplate, out var _);

CheckBenchmark();
}

[Benchmark]
Expand Down
4 changes: 3 additions & 1 deletion Fluid.Benchmarks/DotLiquidBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using DotLiquid;
using DotLiquid;
using System.Linq;

namespace Fluid.Benchmarks
Expand All @@ -11,6 +11,8 @@ public DotLiquidBenchmarks()
{
_dotLiquidTemplate = Template.Parse(ProductTemplate);
_dotLiquidTemplate.MakeThreadSafe();

CheckBenchmark();
}

private Hash MakeProducts()
Expand Down
4 changes: 3 additions & 1 deletion Fluid.Benchmarks/FluidBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ public class FluidBenchmarks : BaseBenchmarks

public FluidBenchmarks()
{
_options.MemberAccessStrategy.Register<Product>();
_options.MemberAccessStrategy.MemberNameStrategy = MemberNameStrategies.CamelCase;
_options.MemberAccessStrategy.Register<Product>();
_parser.TryParse(ProductTemplate, out _fluidTemplate, out var _);

CheckBenchmark();
}

[Benchmark]
Expand Down
27 changes: 24 additions & 3 deletions Fluid.Benchmarks/HandlebarsBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using HandlebarsDotNet;
using HandlebarsDotNet;
using System;

namespace Fluid.Benchmarks
Expand All @@ -9,7 +9,28 @@ public class HandlebarsBenchmarks : BaseBenchmarks

public HandlebarsBenchmarks()
{
_handlebarsTemplate = Handlebars.Compile(ProductTemplateMustache);
_handlebarsTemplate = CompileTemplate(ProductTemplateMustache);
CheckBenchmark();
}

private HandlebarsTemplate<object, object> CompileTemplate(string template)
{
var handlebars = Handlebars.Create();

using (handlebars.Configure())
{
handlebars.RegisterHelper("truncate", (output, options, context, arguments) =>
{
const string ellipsisStr = "...";
var inputStr = options.Template();
var length = Convert.ToInt32(arguments.Length > 0 ? arguments[0] : 50);
var l = Math.Max(0, length - ellipsisStr.Length);
var concat = string.Concat(inputStr.AsSpan().Slice(0, l), ellipsisStr);
output.WriteSafeString(concat);
});

return handlebars.Compile(ProductTemplateMustache);
}
}

public override object Parse()
Expand All @@ -32,7 +53,7 @@ public override string Render()

public override string ParseAndRender()
{
var template = Handlebars.Compile(ProductTemplateMustache);
var template = CompileTemplate(ProductTemplateMustache);
return template(new { products = Products });
}
}
Expand Down
5 changes: 4 additions & 1 deletion Fluid.Benchmarks/LiquidNetBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Liquid.NET;
using Liquid.NET;
using Liquid.NET.Utils;

namespace Fluid.Benchmarks
Expand All @@ -10,6 +10,7 @@ public class LiquidNetBenchmarks : BaseBenchmarks
public LiquidNetBenchmarks()
{
_liquidNetTemplate = LiquidTemplate.Create(ProductTemplate);
CheckBenchmark();
}

public override object Parse()
Expand All @@ -25,6 +26,7 @@ public override object ParseBig()
public override string Render()
{
var context = new Liquid.NET.TemplateContext();
context.WithAllFilters();
context.DefineLocalVariable("products", Products.ToLiquid());
return _liquidNetTemplate.LiquidTemplate.Render(context).Result;
}
Expand All @@ -33,6 +35,7 @@ public override string ParseAndRender()
{
var template = LiquidTemplate.Create(ProductTemplate);
var context = new Liquid.NET.TemplateContext();
context.WithAllFilters();
context.DefineLocalVariable("products", Products.ToLiquid());
return template.LiquidTemplate.Render(context).Result;
}
Expand Down
2 changes: 1 addition & 1 deletion Fluid.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Running;

namespace Fluid.Benchmarks
{
Expand Down
4 changes: 3 additions & 1 deletion Fluid.Benchmarks/ScribanBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Scriban;
using Scriban;
using Scriban.Runtime;

namespace Fluid.Benchmarks
Expand All @@ -10,6 +10,8 @@ public class ScribanBenchmarks : BaseBenchmarks
public ScribanBenchmarks()
{
_scribanTemplate = Template.ParseLiquid(ProductTemplate);

CheckBenchmark();
}

public override object Parse()
Expand Down
4 changes: 2 additions & 2 deletions Fluid.Benchmarks/product.mustache
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<ul id='products'>
<ul id='products'>
{{#products}}
<li>
<h2>{{ name }}</h2>
Only {{ price }}
{{#truncate}}{{description}}{{/truncate}}
{{#truncate 15}}{{description}}{{/truncate}}
</li>
{{/products}}
</ul>