diff --git a/CliFx.Benchmarks/Benchmark.cs b/CliFx.Benchmarks/Benchmark.cs new file mode 100644 index 0000000..21de1df --- /dev/null +++ b/CliFx.Benchmarks/Benchmark.cs @@ -0,0 +1,34 @@ +using System.Threading.Tasks; +using BenchmarkDotNet.Attributes; +using CliFx.Benchmarks.Commands; + +namespace CliFx.Benchmarks +{ + [CoreJob] + [RankColumn] + public class Benchmark + { + private static readonly string[] Arguments = { "--str", "hello world", "-i", "13", "-b" }; + + [Benchmark(Description = "CliFx", Baseline = true)] + public Task ExecuteWithCliFx() => new CliApplication(new[] {typeof(CliFxCommand)}).RunAsync(Arguments); + + [Benchmark(Description = "System.CommandLine")] + public Task ExecuteWithSystemCommandLine() => new SystemCommandLineCommand().ExecuteAsync(Arguments); + + [Benchmark(Description = "McMaster.Extensions.CommandLineUtils")] + public int ExecuteWithMcMaster() => McMaster.Extensions.CommandLineUtils.CommandLineApplication.Execute(Arguments); + + // Skipped because this benchmark freezes after a couple of iterations + // Probably wasn't designed to run multiple times in single process execution + //[Benchmark(Description = "CommandLineParser")] + public void ExecuteWithCommandLineParser() + { + var parsed = CommandLine.Parser.Default.ParseArguments(Arguments, typeof(CommandLineParserCommand)); + CommandLine.ParserResultExtensions.WithParsed(parsed, c => c.Execute()); + } + + [Benchmark(Description = "PowerArgs")] + public void ExecuteWithPowerArgs() => PowerArgs.Args.InvokeMain(Arguments); + } +} \ No newline at end of file diff --git a/CliFx.Benchmarks/CliFx.Benchmarks.csproj b/CliFx.Benchmarks/CliFx.Benchmarks.csproj new file mode 100644 index 0000000..fe59d2c --- /dev/null +++ b/CliFx.Benchmarks/CliFx.Benchmarks.csproj @@ -0,0 +1,21 @@ + + + + Exe + netcoreapp2.2 + latest + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CliFx.Benchmarks/Commands/CliFxCommand.cs b/CliFx.Benchmarks/Commands/CliFxCommand.cs new file mode 100644 index 0000000..53ac534 --- /dev/null +++ b/CliFx.Benchmarks/Commands/CliFxCommand.cs @@ -0,0 +1,21 @@ +using System.Threading.Tasks; +using CliFx.Attributes; +using CliFx.Models; + +namespace CliFx.Benchmarks.Commands +{ + [Command] + public class CliFxCommand : ICommand + { + [CommandOption("str", 's')] + public string StrOption { get; set; } + + [CommandOption("int", 'i')] + public int IntOption { get; set; } + + [CommandOption("bool", 'b')] + public bool BoolOption { get; set; } + + public Task ExecuteAsync(CommandContext context) => Task.CompletedTask; + } +} diff --git a/CliFx.Benchmarks/Commands/CommandLineParserCommand.cs b/CliFx.Benchmarks/Commands/CommandLineParserCommand.cs new file mode 100644 index 0000000..8ffbc1f --- /dev/null +++ b/CliFx.Benchmarks/Commands/CommandLineParserCommand.cs @@ -0,0 +1,20 @@ +using CommandLine; + +namespace CliFx.Benchmarks.Commands +{ + public class CommandLineParserCommand + { + [Option('s', "str")] + public string StrOption { get; set; } + + [Option('i', "int")] + public int IntOption { get; set; } + + [Option('b', "bool")] + public bool BoolOption { get; set; } + + public void Execute() + { + } + } +} \ No newline at end of file diff --git a/CliFx.Benchmarks/Commands/McMasterCommand.cs b/CliFx.Benchmarks/Commands/McMasterCommand.cs new file mode 100644 index 0000000..57a15d7 --- /dev/null +++ b/CliFx.Benchmarks/Commands/McMasterCommand.cs @@ -0,0 +1,18 @@ +using McMaster.Extensions.CommandLineUtils; + +namespace CliFx.Benchmarks.Commands +{ + public class McMasterCommand + { + [Option("--str|-s")] + public string StrOption { get; set; } + + [Option("--int|-i")] + public int IntOption { get; set; } + + [Option("--bool|-b")] + public bool BoolOption { get; set; } + + public int OnExecute() => 0; + } +} \ No newline at end of file diff --git a/CliFx.Benchmarks/Commands/PowerArgsCommand.cs b/CliFx.Benchmarks/Commands/PowerArgsCommand.cs new file mode 100644 index 0000000..003dc2d --- /dev/null +++ b/CliFx.Benchmarks/Commands/PowerArgsCommand.cs @@ -0,0 +1,20 @@ +using PowerArgs; + +namespace CliFx.Benchmarks.Commands +{ + public class PowerArgsCommand + { + [ArgShortcut("--str"), ArgShortcut("-s")] + public string StrOption { get; set; } + + [ArgShortcut("--int"), ArgShortcut("-i")] + public int IntOption { get; set; } + + [ArgShortcut("--bool"), ArgShortcut("-b")] + public bool BoolOption { get; set; } + + public void Main() + { + } + } +} \ No newline at end of file diff --git a/CliFx.Benchmarks/Commands/SystemCommandLineCommand.cs b/CliFx.Benchmarks/Commands/SystemCommandLineCommand.cs new file mode 100644 index 0000000..dd9de9b --- /dev/null +++ b/CliFx.Benchmarks/Commands/SystemCommandLineCommand.cs @@ -0,0 +1,34 @@ +using System.CommandLine; +using System.CommandLine.Invocation; +using System.Threading.Tasks; + +namespace CliFx.Benchmarks.Commands +{ + public class SystemCommandLineCommand + { + public static int ExecuteHandler(string s, int i, bool b) => 0; + + public Task ExecuteAsync(string[] args) + { + var command = new RootCommand + { + new Option(new[] {"--str", "-s"}) + { + Argument = new Argument() + }, + new Option(new[] {"--int", "-i"}) + { + Argument = new Argument() + }, + new Option(new[] {"--bool", "-b"}) + { + Argument = new Argument() + } + }; + + command.Handler = CommandHandler.Create(typeof(SystemCommandLineCommand).GetMethod(nameof(ExecuteHandler))); + + return command.InvokeAsync(args); + } + } +} \ No newline at end of file diff --git a/CliFx.Benchmarks/Program.cs b/CliFx.Benchmarks/Program.cs new file mode 100644 index 0000000..ad995ca --- /dev/null +++ b/CliFx.Benchmarks/Program.cs @@ -0,0 +1,12 @@ +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Running; + +namespace CliFx.Benchmarks +{ + public static class Program + { + public static void Main() => + BenchmarkRunner.Run(typeof(Program).Assembly, DefaultConfig.Instance + .With(ConfigOptions.DisableOptimizationsValidator)); + } +} \ No newline at end of file diff --git a/CliFx.sln b/CliFx.sln index fe0a064..1c10759 100644 --- a/CliFx.sln +++ b/CliFx.sln @@ -16,6 +16,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Readme.md = Readme.md EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CliFx.Benchmarks", "CliFx.Benchmarks\CliFx.Benchmarks.csproj", "{8ACD6DC2-D768-4850-9223-5B7C83A78513}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -62,6 +64,18 @@ Global {4904B3EB-3286-4F1B-8B74-6FF051C8E787}.Release|x64.Build.0 = Release|Any CPU {4904B3EB-3286-4F1B-8B74-6FF051C8E787}.Release|x86.ActiveCfg = Release|Any CPU {4904B3EB-3286-4F1B-8B74-6FF051C8E787}.Release|x86.Build.0 = Release|Any CPU + {8ACD6DC2-D768-4850-9223-5B7C83A78513}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8ACD6DC2-D768-4850-9223-5B7C83A78513}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8ACD6DC2-D768-4850-9223-5B7C83A78513}.Debug|x64.ActiveCfg = Debug|Any CPU + {8ACD6DC2-D768-4850-9223-5B7C83A78513}.Debug|x64.Build.0 = Debug|Any CPU + {8ACD6DC2-D768-4850-9223-5B7C83A78513}.Debug|x86.ActiveCfg = Debug|Any CPU + {8ACD6DC2-D768-4850-9223-5B7C83A78513}.Debug|x86.Build.0 = Debug|Any CPU + {8ACD6DC2-D768-4850-9223-5B7C83A78513}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8ACD6DC2-D768-4850-9223-5B7C83A78513}.Release|Any CPU.Build.0 = Release|Any CPU + {8ACD6DC2-D768-4850-9223-5B7C83A78513}.Release|x64.ActiveCfg = Release|Any CPU + {8ACD6DC2-D768-4850-9223-5B7C83A78513}.Release|x64.Build.0 = Release|Any CPU + {8ACD6DC2-D768-4850-9223-5B7C83A78513}.Release|x86.ActiveCfg = Release|Any CPU + {8ACD6DC2-D768-4850-9223-5B7C83A78513}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Readme.md b/Readme.md index 5f0ee48..8e6846d 100644 --- a/Readme.md +++ b/Readme.md @@ -28,8 +28,9 @@ To be added with a stable release... ## Libraries used - [NUnit](https://github.com/nunit/nunit) -- [FluentAssertions](https://github.com/fluentassertions/fluentassertions) - [CliWrap](https://github.com/Tyrrrz/CliWrap) +- [FluentAssertions](https://github.com/fluentassertions/fluentassertions) +- [BenchmarkDotNet](https://github.com/dotnet/BenchmarkDotNet) - [Coverlet](https://github.com/tonerdo/coverlet) ## Donate