Skip to content

Commit 29dc301

Browse files
committed
update benchmark
1 parent 6fcbe84 commit 29dc301

File tree

5 files changed

+46
-16
lines changed

5 files changed

+46
-16
lines changed

ReadMe.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
ConsoleAppFramework v5 is Zero Dependency, Zero Overhead, Zero Reflection, Zero Allocation, AOT Safe CLI Framework powered by C# Source Generator; achieves exceptionally high performance, fastest start-up time(with NativeAOT) and minimal binary size. Leveraging the latest features of .NET 8 and C# 13 ([IncrementalGenerator](https://github.com/dotnet/roslyn/blob/main/docs/features/incremental-generators.md), [managed function pointer](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/function-pointers#function-pointers-1), [params arrays and default values lambda expression](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-expressions#input-parameters-of-a-lambda-expression), [`ISpanParsable<T>`](https://learn.microsoft.com/en-us/dotnet/api/system.ispanparsable-1), [`PosixSignalRegistration`](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.posixsignalregistration), etc.), this library ensures maximum performance while maintaining flexibility and extensibility.
66

7-
![image](https://github.com/Cysharp/ConsoleAppFramework/assets/46207/db4bf599-9fe0-4ce4-801f-0003f44d5628)
7+
![image](https://github.com/user-attachments/assets/4a10fd2b-fa56-467f-8d7f-e47bee634753)
88
> Set `RunStrategy=ColdStart WarmupCount=0` to calculate the cold start benchmark, which is suitable for CLI application.
99
1010
The magical performance is achieved by statically generating everything and parsing inline. Let's take a look at a minimal example:
@@ -746,8 +746,6 @@ While there are some standards for command-line arguments, such as UNIX tools an
746746

747747
For example, specifications that change behavior based on `-x` and `-X` or allow bundling `-f -d -x` as `-fdx` are not easy to understand and also take time to parse. The poor performance of System.CommandLine may be influenced by its adherence to complex grammar. Therefore, ConsoleAppFramework prioritizes performance and clear rules. It uses lower-kebab-case as the basis while allowing case-insensitive matching. It does not support ambiguous grammar that cannot be processed in a single pass or takes time to parse.
748748

749-
[System.CommandLine seems to be aiming for a new direction in .NET 9 and .NET 10](https://github.com/dotnet/command-line-api/issues/2338), but from a performance perspective, it will never surpass ConsoleAppFramework.
750-
751749
CancellationToken(Gracefully Shutdown) and Timeout
752750
---
753751
In ConsoleAppFramework, when you pass a `CancellationToken` as an argument, it can be used to check for interruption commands (SIGINT/SIGTERM/SIGKILL - Ctrl+C) rather than being treated as a parameter. For handling this, ConsoleAppFramework performs special code generation when a `CancellationToken` is included in the parameters.

sandbox/CliFrameworkBenchmark/Benchmark.cs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,16 @@ public ValueTask<int> ExecuteWithCliFx()
3737
return new CliApplicationBuilder().AddCommand(typeof(CliFxCommand)).Build().RunAsync(Arguments);
3838
}
3939

40-
[Benchmark(Description = "System.CommandLine")]
40+
[Benchmark(Description = "System.CommandLine v2")]
4141
public int ExecuteWithSystemCommandLine()
4242
{
43-
return new SystemCommandLineCommand().Execute(Arguments);
43+
return SystemCommandLineCommand.ParseInvoke(Arguments);
44+
}
45+
46+
[Benchmark(Description = "System.CommandLine v2(InvokeAsync)")]
47+
public Task<int> ExecuteWithSystemCommandLineAsync()
48+
{
49+
return SystemCommandLineCommand.ParseInvokeAsync(Arguments);
4450
}
4551

4652
//[Benchmark(Description = "McMaster.Extensions.CommandLineUtils")]
@@ -69,9 +75,17 @@ public int ExecuteWithSystemCommandLine()
6975
//}
7076

7177
[Benchmark(Description = "ConsoleAppFramework v5", Baseline = true)]
72-
public unsafe void ExecuteConsoleAppFramework()
78+
public void ExecuteConsoleAppFramework()
79+
{
80+
ConsoleApp.Run(Arguments, ConsoleAppFrameworkCommand.Execute);
81+
}
82+
83+
[Benchmark(Description = "ConsoleAppFramework v5(app with CancellationToken)")]
84+
public Task ExecuteConsoleAppFramework2()
7385
{
74-
ConsoleApp.Run(Arguments, &ConsoleAppFrameworkCommandWithCancellationToken.Execute);
86+
var app = ConsoleApp.Create();
87+
app.Add("", ConsoleAppFrameworkCommand.ExecuteWithCancellationToken);
88+
return app.RunAsync(Arguments);
7589
}
7690

7791
// for alpha testing

sandbox/CliFrameworkBenchmark/Commands/ConsoleAppFrameworkCommand.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,16 @@ public static void Execute(string? str, int intOption, bool boolOption)
2929
{
3030

3131
}
32-
}
3332

34-
public class ConsoleAppFrameworkCommandWithCancellationToken
35-
{
3633
/// <summary>
3734
///
3835
/// </summary>
3936
/// <param name="str">-s</param>
4037
/// <param name="intOption">-i</param>
4138
/// <param name="boolOption">-b</param>
42-
public static void Execute(string? str, int intOption, bool boolOption, CancellationToken cancellationToken)
39+
public static Task ExecuteWithCancellationToken(string? str, int intOption, bool boolOption, CancellationToken cancellationToken)
4340
{
44-
41+
return Task.CompletedTask;
4542
}
4643
}
4744

sandbox/CliFrameworkBenchmark/Commands/SystemCommandLineCommand.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace Cocona.Benchmark.External.Commands;
66

77
public class SystemCommandLineCommand
88
{
9-
public int Execute(string[] args)
9+
public static int ParseInvoke(string[] args)
1010
{
1111
var stringOption = new Option<string>("--str", "-s");
1212
var intOption = new Option<int>("--int", "-i");
@@ -23,4 +23,23 @@ public int Execute(string[] args)
2323

2424
return command.Parse(args).Invoke();
2525
}
26+
27+
public static Task<int> ParseInvokeAsync(string[] args)
28+
{
29+
var stringOption = new Option<string>("--str", "-s");
30+
var intOption = new Option<int>("--int", "-i");
31+
var boolOption = new Option<bool>("--bool", "-b");
32+
33+
var command = new RootCommand { stringOption, intOption, boolOption };
34+
35+
command.SetAction((parseResult, cancellationToken) =>
36+
{
37+
_ = parseResult.GetValue(stringOption);
38+
_ = parseResult.GetValue(intOption);
39+
_ = parseResult.GetValue(boolOption);
40+
return Task.CompletedTask;
41+
});
42+
43+
return command.Parse(args).InvokeAsync();
44+
}
2645
}

sandbox/CliFrameworkBenchmark/Program.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,20 @@ static void Main(string[] args)
1818
{
1919
var config = DefaultConfig.Instance
2020
.WithSummaryStyle(SummaryStyle.Default
21-
.WithTimeUnit(TimeUnit.Millisecond));
21+
.WithTimeUnit(TimeUnit.Millisecond))
22+
.HideColumns(BenchmarkDotNet.Columns.Column.Error)
23+
;
2224

2325
config.AddDiagnoser(MemoryDiagnoser.Default);
24-
config.AddDiagnoser(new ThreadingDiagnoser(new ThreadingDiagnoserConfig(displayLockContentionWhenZero: false, displayCompletedWorkItemCountWhenZero: false)));
26+
// config.AddDiagnoser(new ThreadingDiagnoser(new ThreadingDiagnoserConfig(displayLockContentionWhenZero: false, displayCompletedWorkItemCountWhenZero: false)));
2527

2628
config.AddJob(Job.Default
2729
.WithStrategy(RunStrategy.ColdStart)
2830
.WithLaunchCount(1)
2931
.WithWarmupCount(0)
3032
.WithIterationCount(1)
3133
.WithInvocationCount(1)
32-
.WithToolchain(CsProjCoreToolchain.NetCoreApp80)
34+
.WithToolchain(CsProjCoreToolchain.NetCoreApp10_0) // .NET 10
3335
.DontEnforcePowerPlan());
3436

3537
BenchmarkRunner.Run<Benchmark>(config, args);

0 commit comments

Comments
 (0)