diff --git a/src/Benchmark.Development/Benchmark.Development.csproj b/src/Benchmark.Development/Benchmark.Development.csproj new file mode 100644 index 00000000..572bdf29 --- /dev/null +++ b/src/Benchmark.Development/Benchmark.Development.csproj @@ -0,0 +1,26 @@ + + + + Exe + net10.0 + true + enable + enable + True + Benchmark.Development.snk + False + 7.4.0 + 12.0 + + + + + + + + + + + + + diff --git a/src/Benchmark.Development/Benchmark.Development.snk b/src/Benchmark.Development/Benchmark.Development.snk new file mode 100644 index 00000000..beae8ece Binary files /dev/null and b/src/Benchmark.Development/Benchmark.Development.snk differ diff --git a/src/Benchmark.Development/Benchmarks/Config.cs b/src/Benchmark.Development/Benchmarks/Config.cs new file mode 100644 index 00000000..554581ab --- /dev/null +++ b/src/Benchmark.Development/Benchmarks/Config.cs @@ -0,0 +1,54 @@ +using BenchmarkDotNet.Columns; +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Diagnosers; +using BenchmarkDotNet.Exporters; +using BenchmarkDotNet.Exporters.Csv; +using BenchmarkDotNet.Jobs; +using BenchmarkDotNet.Loggers; +using Perfolizer.Models; + +namespace Benchmark.Benchmarks +{ + public class Config : ManualConfig + { + public Config() + { + AddLogger(ConsoleLogger.Default); + + AddExporter(CsvExporter.Default); + AddExporter(MarkdownExporter.GitHub); + AddExporter(HtmlExporter.Default); + + AddDiagnoser(MemoryDiagnoser.Default); + AddColumn(TargetMethodColumn.Method); + + AddColumn(JobCharacteristicColumn.AllColumns); + AddColumnProvider(DefaultColumnProviders.Params); + AddColumn(StatisticColumn.Mean); + + AddColumn(StatisticColumn.StdDev); + AddColumn(StatisticColumn.Error); + + AddColumn(BaselineRatioColumn.RatioMean); + AddColumnProvider(DefaultColumnProviders.Metrics); + + string[] targetVersions = [ + "7.4.0", + "9.0.0-pre01", + ]; + + foreach (var version in targetVersions) + { + AddJob(Job.ShortRun + .WithLaunchCount(1) + .WithWarmupCount(2) + .WithIterationCount(10) + .WithMsBuildArguments($"/p:SciVersion={version}") + .WithId($"v{version}") + ); + } + + Options |= ConfigOptions.JoinSummary; + } + } +} \ No newline at end of file diff --git a/src/Benchmark.Development/Benchmarks/TestAll.cs b/src/Benchmark.Development/Benchmarks/TestAll.cs new file mode 100644 index 00000000..b3e28a76 --- /dev/null +++ b/src/Benchmark.Development/Benchmarks/TestAll.cs @@ -0,0 +1,30 @@ +using Benchmark.Classes; +using BenchmarkDotNet.Attributes; + +namespace Benchmark.Benchmarks +{ + public class TestAll + { + private Foo _fooInstance; + private Customer _customerInstance; + + [Params(100_000)]//, 1_000_000)] + public int Iterations { get; set; } + + [Benchmark] + public void MapsterTest() + { + TestAdaptHelper.TestMapsterAdapter(_fooInstance, Iterations); + TestAdaptHelper.TestMapsterAdapter(_customerInstance, Iterations); + } + + [GlobalSetup(Target = nameof(MapsterTest))] + public void SetupMapster() + { + _fooInstance = TestAdaptHelper.SetupFooInstance(); + _customerInstance = TestAdaptHelper.SetupCustomerInstance(); + TestAdaptHelper.ConfigureMapster(_fooInstance, MapsterCompilerType.Default); + TestAdaptHelper.ConfigureMapster(_customerInstance, MapsterCompilerType.Default); + } + } +} \ No newline at end of file diff --git a/src/Benchmark.Development/Benchmarks/TestComplexTypes.cs b/src/Benchmark.Development/Benchmarks/TestComplexTypes.cs new file mode 100644 index 00000000..62d7a764 --- /dev/null +++ b/src/Benchmark.Development/Benchmarks/TestComplexTypes.cs @@ -0,0 +1,26 @@ +using Benchmark.Classes; +using BenchmarkDotNet.Attributes; + +namespace Benchmark.Benchmarks +{ + public class TestComplexTypes + { + private Customer _customerInstance; + + [Params(1000, 10_000, 100_000, 1_000_000)] + public int Iterations { get; set; } + + [Benchmark] + public void MapsterTest() + { + TestAdaptHelper.TestMapsterAdapter(_customerInstance, Iterations); + } + + [GlobalSetup(Target = nameof(MapsterTest))] + public void SetupMapster() + { + _customerInstance = TestAdaptHelper.SetupCustomerInstance(); + TestAdaptHelper.ConfigureMapster(_customerInstance, MapsterCompilerType.Default); + } + } +} \ No newline at end of file diff --git a/src/Benchmark.Development/Benchmarks/TestSimpleTypes.cs b/src/Benchmark.Development/Benchmarks/TestSimpleTypes.cs new file mode 100644 index 00000000..8678a8ec --- /dev/null +++ b/src/Benchmark.Development/Benchmarks/TestSimpleTypes.cs @@ -0,0 +1,26 @@ +using Benchmark.Classes; +using BenchmarkDotNet.Attributes; + +namespace Benchmark.Benchmarks +{ + public class TestSimpleTypes + { + private Foo _fooInstance; + + [Params(1000, 10_000, 100_000, 1_000_000)] + public int Iterations { get; set; } + + [Benchmark] + public void MapsterTest() + { + TestAdaptHelper.TestMapsterAdapter(_fooInstance, Iterations); + } + + [GlobalSetup(Target = nameof(MapsterTest))] + public void SetupMapster() + { + _fooInstance = TestAdaptHelper.SetupFooInstance(); + TestAdaptHelper.ConfigureMapster(_fooInstance, MapsterCompilerType.Default); + } + } +} \ No newline at end of file diff --git a/src/Benchmark.Development/Classes/Customer.cs b/src/Benchmark.Development/Classes/Customer.cs new file mode 100644 index 00000000..5fac9cef --- /dev/null +++ b/src/Benchmark.Development/Classes/Customer.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; + +namespace Benchmark.Classes +{ + public class Address + { + public int Id { get; set; } + public string Street { get; set; } + public string City { get; set; } + public string Country { get; set; } + } + + public class AddressDTO + { + public int Id { get; set; } + public string City { get; set; } + public string Country { get; set; } + } + + public class Customer + { + public int Id { get; set; } + public string Name { get; set; } + public decimal? Credit { get; set; } + public Address Address { get; set; } + public Address HomeAddress { get; set; } + public Address[] Addresses { get; set; } + public ICollection
WorkAddresses { get; set; } + } + + public class CustomerDTO + { + public int Id { get; set; } + public string Name { get; set; } + public Address Address { get; set; } + public AddressDTO HomeAddress { get; set; } + public AddressDTO[] Addresses { get; set; } + public List WorkAddresses { get; set; } + public string AddressCity { get; set; } + } +} diff --git a/src/Benchmark.Development/Classes/Foo.cs b/src/Benchmark.Development/Classes/Foo.cs new file mode 100644 index 00000000..063541b8 --- /dev/null +++ b/src/Benchmark.Development/Classes/Foo.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; + +namespace Benchmark.Classes +{ + public class Foo + { + public string Name { get; set; } + + public int Int32 { get; set; } + + public long Int64 { set; get; } + + public int? NullInt { get; set; } + + public float Floatn { get; set; } + + public double Doublen { get; set; } + + public DateTime DateTime { get; set; } + + public Foo Foo1 { get; set; } + + public IEnumerable Foos { get; set; } + + public Foo[] FooArr { get; set; } + + public int[] IntArr { get; set; } + + public IEnumerable Ints { get; set; } + } +} diff --git a/src/Benchmark.Development/Directory.Build.props b/src/Benchmark.Development/Directory.Build.props new file mode 100644 index 00000000..8c415f63 --- /dev/null +++ b/src/Benchmark.Development/Directory.Build.props @@ -0,0 +1,18 @@ + + + + false + + + + chaowlert;eric_swann;andrerav + Copyright (c) $([System.DateTime]::Now.ToString(`yyyy`)) Chaowlert Chaisrichalermpol, Eric Swann, Andreas Ravnestad + false + + MIT + false + true + false + 12 + + \ No newline at end of file diff --git a/src/Benchmark.Development/Program.cs b/src/Benchmark.Development/Program.cs new file mode 100644 index 00000000..32e641ed --- /dev/null +++ b/src/Benchmark.Development/Program.cs @@ -0,0 +1,11 @@ +using Benchmark.Benchmarks; +using BenchmarkDotNet.Running; + +var switcher = new BenchmarkSwitcher(new[] + { + typeof(TestSimpleTypes), + typeof(TestComplexTypes), + typeof(TestAll), + }); + +switcher.Run(args, new Config()); diff --git a/src/Benchmark.Development/TestAdaptHelper.cs b/src/Benchmark.Development/TestAdaptHelper.cs new file mode 100644 index 00000000..c6e06739 --- /dev/null +++ b/src/Benchmark.Development/TestAdaptHelper.cs @@ -0,0 +1,105 @@ +using Benchmark.Classes; +using Mapster; +using System.Linq.Expressions; + +namespace Benchmark +{ + public static class TestAdaptHelper + { + + public static Customer SetupCustomerInstance() + { + return new Customer + { + Address = new Address { City = "istanbul", Country = "turkey", Id = 1, Street = "istiklal cad." }, + HomeAddress = new Address { City = "istanbul", Country = "turkey", Id = 2, Street = "istiklal cad." }, + Id = 1, + Name = "Eduardo Najera", + Credit = 234.7m, + WorkAddresses = new List
+ { + new Address {City = "istanbul", Country = "turkey", Id = 5, Street = "istiklal cad."}, + new Address {City = "izmir", Country = "turkey", Id = 6, Street = "konak"} + }, + Addresses = new[] + { + new Address {City = "istanbul", Country = "turkey", Id = 3, Street = "istiklal cad."}, + new Address {City = "izmir", Country = "turkey", Id = 4, Street = "konak"} + } + }; + } + + public static Foo SetupFooInstance() + { + return new Foo + { + Name = "foo", + Int32 = 12, + Int64 = 123123, + NullInt = 16, + DateTime = DateTime.Now, + Doublen = 2312112, + Foo1 = new Foo { Name = "foo one" }, + Foos = new List + { + new Foo {Name = "j1", Int64 = 123, NullInt = 321}, + new Foo {Name = "j2", Int32 = 12345, NullInt = 54321}, + new Foo {Name = "j3", Int32 = 12345, NullInt = 54321} + }, + FooArr = new[] + { + new Foo {Name = "a1"}, + new Foo {Name = "a2"}, + new Foo {Name = "a3"} + }, + IntArr = new[] { 1, 2, 3, 4, 5 }, + Ints = new[] { 7, 8, 9 } + }; + } + + private static readonly Func _defaultCompiler = TypeAdapterConfig.GlobalSettings.Compiler; + + private static void SetupCompiler(MapsterCompilerType type) + { + TypeAdapterConfig.GlobalSettings.Compiler = type switch + { + MapsterCompilerType.Default => _defaultCompiler, + // MapsterCompilerType.Roslyn => exp => exp.CompileWithDebugInfo(), + // MapsterCompilerType.FEC => exp => exp.CompileFast(), + _ => throw new ArgumentOutOfRangeException(nameof(type)), + }; + } + public static void ConfigureMapster(Foo fooInstance, MapsterCompilerType type) + { + SetupCompiler(type); + TypeAdapterConfig.GlobalSettings.Compile(typeof(Foo), typeof(Foo)); //recompile + fooInstance.Adapt(); //exercise + } + + public static void ConfigureMapster(Customer customerInstance, MapsterCompilerType type) + { + SetupCompiler(type); + TypeAdapterConfig.GlobalSettings.Compile(typeof(Customer), typeof(CustomerDTO)); //recompile + customerInstance.Adapt(); //exercise + } + + public static void TestMapsterAdapter(TSrc item, int iterations) + where TSrc : class + where TDest : class, new() + { + Loop(item, get => get.Adapt(), iterations); + } + + private static void Loop(T item, Action action, int iterations) + { + for (var i = 0; i < iterations; i++) action(item); + } + } + + public enum MapsterCompilerType + { + Default, + Roslyn, + FEC, + } +} \ No newline at end of file diff --git a/src/Mapster.sln b/src/Mapster.sln index befd616f..57696e45 100644 --- a/src/Mapster.sln +++ b/src/Mapster.sln @@ -63,6 +63,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TemplateTest", "TemplateTes EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mapster.Tool.Tests", "Mapster.Tool.Tests\Mapster.Tool.Tests.csproj", "{E64E9CEB-8FB2-4012-BBA8-4C2B99FD54C1}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmark.Development", "Benchmark.Development\Benchmark.Development.csproj", "{5F29425E-DFC6-48C2-945A-FC5D91260C07}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -161,6 +163,10 @@ Global {E64E9CEB-8FB2-4012-BBA8-4C2B99FD54C1}.Debug|Any CPU.Build.0 = Debug|Any CPU {E64E9CEB-8FB2-4012-BBA8-4C2B99FD54C1}.Release|Any CPU.ActiveCfg = Release|Any CPU {E64E9CEB-8FB2-4012-BBA8-4C2B99FD54C1}.Release|Any CPU.Build.0 = Release|Any CPU + {5F29425E-DFC6-48C2-945A-FC5D91260C07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5F29425E-DFC6-48C2-945A-FC5D91260C07}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5F29425E-DFC6-48C2-945A-FC5D91260C07}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5F29425E-DFC6-48C2-945A-FC5D91260C07}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE