From 0a692bc7438f659c54f774a7f3ceddf0ca7abed4 Mon Sep 17 00:00:00 2001 From: Patrik Svensson Date: Tue, 20 Jan 2026 18:03:49 +0100 Subject: [PATCH] Add benchmarks for rendering --- .gitignore | 4 + ...Benchmarks.AnsiBenchmarks-report-github.md | 17 ++++ ...nchmarks.RenderBenchmarks-report-github.md | 17 ++++ src/Benchmarks/Benchmarks.csproj | 21 +++++ src/Benchmarks/Program.cs | 84 +++++++++++++++++++ src/Directory.Packages.props | 1 + src/Spectre.Console.slnx | 1 + 7 files changed, 145 insertions(+) create mode 100644 src/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.AnsiBenchmarks-report-github.md create mode 100644 src/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.RenderBenchmarks-report-github.md create mode 100644 src/Benchmarks/Benchmarks.csproj create mode 100644 src/Benchmarks/Program.cs diff --git a/.gitignore b/.gitignore index 537737dd..0f148ac9 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,10 @@ dotnet-install.sh* *.lock.json +# Benchmarks +**/BenchmarkDotNet.Artifacts/**/*.* +!**/BenchmarkDotNet.Artifacts/**/*.md + # Visual Studio .vs/ .vscode/ diff --git a/src/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.AnsiBenchmarks-report-github.md b/src/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.AnsiBenchmarks-report-github.md new file mode 100644 index 00000000..4222ac88 --- /dev/null +++ b/src/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.AnsiBenchmarks-report-github.md @@ -0,0 +1,17 @@ +``` + +BenchmarkDotNet v0.15.8, macOS Tahoe 26.2 (25C56) [Darwin 25.2.0] +Apple M3 Pro, 1 CPU, 11 logical and 11 physical cores +.NET SDK 10.0.101 + [Host] : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a + .NET 10.0 : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a + .NET 8.0 : .NET 8.0.17 (8.0.17, 8.0.1725.26602), Arm64 RyuJIT armv8.0-a + .NET 9.0 : .NET 9.0.10 (9.0.10, 9.0.1025.47515), Arm64 RyuJIT armv8.0-a + + +``` +| Method | Job | Runtime | Mean | Error | StdDev | Gen0 | Gen1 | Allocated | +|----------------- |---------- |---------- |---------:|---------:|---------:|-------:|-------:|----------:| +| RenderableToAnsi | .NET 10.0 | .NET 10.0 | 12.33 μs | 0.054 μs | 0.045 μs | 5.3558 | 0.1831 | 43.87 KB | +| RenderableToAnsi | .NET 8.0 | .NET 8.0 | 14.12 μs | 0.100 μs | 0.094 μs | 5.7068 | 0.1831 | 46.73 KB | +| RenderableToAnsi | .NET 9.0 | .NET 9.0 | 14.12 μs | 0.052 μs | 0.049 μs | 5.6458 | 0.1984 | 46.17 KB | diff --git a/src/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.RenderBenchmarks-report-github.md b/src/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.RenderBenchmarks-report-github.md new file mode 100644 index 00000000..01cd4671 --- /dev/null +++ b/src/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.RenderBenchmarks-report-github.md @@ -0,0 +1,17 @@ +``` + +BenchmarkDotNet v0.15.8, macOS Tahoe 26.2 (25C56) [Darwin 25.2.0] +Apple M3 Pro, 1 CPU, 11 logical and 11 physical cores +.NET SDK 10.0.101 + [Host] : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a + .NET 10.0 : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a + .NET 8.0 : .NET 8.0.17 (8.0.17, 8.0.1725.26602), Arm64 RyuJIT armv8.0-a + .NET 9.0 : .NET 9.0.10 (9.0.10, 9.0.1025.47515), Arm64 RyuJIT armv8.0-a + + +``` +| Method | Job | Runtime | Mean | Error | StdDev | Gen0 | Gen1 | Allocated | +|------- |---------- |---------- |---------:|---------:|---------:|-------:|-------:|----------:| +| Render | .NET 10.0 | .NET 10.0 | 12.45 μs | 0.130 μs | 0.101 μs | 5.4169 | 0.0916 | 44.34 KB | +| Render | .NET 8.0 | .NET 8.0 | 21.74 μs | 0.033 μs | 0.031 μs | 5.7678 | 0.0916 | 47.2 KB | +| Render | .NET 9.0 | .NET 9.0 | 14.37 μs | 0.070 μs | 0.065 μs | 5.7068 | 0.0916 | 46.64 KB | diff --git a/src/Benchmarks/Benchmarks.csproj b/src/Benchmarks/Benchmarks.csproj new file mode 100644 index 00000000..cc72c0ba --- /dev/null +++ b/src/Benchmarks/Benchmarks.csproj @@ -0,0 +1,21 @@ + + + + Exe + net10.0;net9.0;net8.0 + true + true + false + true + false + + + + + + + + + + + diff --git a/src/Benchmarks/Program.cs b/src/Benchmarks/Program.cs new file mode 100644 index 00000000..be2baa75 --- /dev/null +++ b/src/Benchmarks/Program.cs @@ -0,0 +1,84 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Jobs; +using BenchmarkDotNet.Running; +using Spectre.Console; +using Spectre.Console.Rendering; + +namespace Benchmarks; + +public static class Program +{ + public static int Main(string[] args) + { + BenchmarkRunner.Run(typeof(Program).Assembly); + return 0; + } +} + +[MemoryDiagnoser] +[SimpleJob(RuntimeMoniker.Net80)] +[SimpleJob(RuntimeMoniker.Net90)] +[SimpleJob(RuntimeMoniker.Net10_0)] +public class RenderBenchmarks +{ + private IAnsiConsole _console = null!; + private IRenderable _renderable = null!; + + [GlobalSetup] + public void Setup() + { + _console = + AnsiConsole.Create(new AnsiConsoleSettings + { + Ansi = AnsiSupport.Detect, + ColorSystem = ColorSystemSupport.TrueColor, + Out = new AnsiConsoleOutput(new StringWriter()), + Interactive = InteractionSupport.No, + EnvironmentVariables = null + }); + + _renderable = new Table() + .AddColumns("Foo", "Bar") + .AddRow(new Text("1"), new Table() + .AddColumns("Baz", "Qux") + .AddRow("1", "2") + .AddRow("3", "4")); + } + + [Benchmark] + public void Render() => _console.Write(_renderable); +} + +[MemoryDiagnoser] +[SimpleJob(RuntimeMoniker.Net80)] +[SimpleJob(RuntimeMoniker.Net90)] +[SimpleJob(RuntimeMoniker.Net10_0)] +public class AnsiBenchmarks +{ + private IAnsiConsole _console = null!; + private IRenderable _renderable = null!; + + [GlobalSetup] + public void Setup() + { + _console = + AnsiConsole.Create(new AnsiConsoleSettings + { + Ansi = AnsiSupport.Detect, + ColorSystem = ColorSystemSupport.TrueColor, + Out = new AnsiConsoleOutput(new StringWriter()), + Interactive = InteractionSupport.No, + EnvironmentVariables = null + }); + + _renderable = new Table() + .AddColumns("Foo", "Bar") + .AddRow(new Text("1"), new Table() + .AddColumns("Baz", "Qux") + .AddRow("1", "2") + .AddRow("3", "4")); + } + + [Benchmark] + public void RenderableToAnsi() => _console.ToAnsi(_renderable); +} \ No newline at end of file diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index df44f841..e8ebd4cc 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -3,6 +3,7 @@ true + diff --git a/src/Spectre.Console.slnx b/src/Spectre.Console.slnx index ff12edc6..c43e9401 100644 --- a/src/Spectre.Console.slnx +++ b/src/Spectre.Console.slnx @@ -19,6 +19,7 @@ +