diff --git a/benchmarks/AMD.Ryzen.7.PRO.7840U.w.Radeon.780M/PackageAssetsBench-Parsers.md b/benchmarks/AMD.Ryzen.7.PRO.7840U.w.Radeon.780M/PackageAssetsBench-Parsers.md new file mode 100644 index 00000000..5aeee737 --- /dev/null +++ b/benchmarks/AMD.Ryzen.7.PRO.7840U.w.Radeon.780M/PackageAssetsBench-Parsers.md @@ -0,0 +1,26 @@ +``` + +BenchmarkDotNet v0.14.0, Windows 11 (10.0.26100.3775) +AMD Ryzen 7 PRO 7840U w/ Radeon 780M Graphics, 1 CPU, 16 logical and 8 physical cores +.NET SDK 9.0.203 + [Host] : .NET 9.0.4 (9.0.425.16305), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI + Job-DEDWQO : .NET 9.0.4 (9.0.425.16305), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI + +Job=Job-DEDWQO EnvironmentVariables=DOTNET_GCDynamicAdaptationMode=0 Runtime=.NET 9.0 +Toolchain=net90 InvocationCount=Default IterationTime=350ms +MaxIterationCount=15 MinIterationCount=5 WarmupCount=6 +Quotes=False Reader=String + +``` +| Method | Parser | Scope | Rows | Mean | MB | MB/s | ns/row | Allocated | +|------- |--------------------------------------- |------ |------ |-----------:|---:|-------:|-------:|----------:| +| Sep_ | SepParserAvx2PackCmpOrMoveMaskTzcnt | Row | 50000 | 3.385 ms | 29 | 8619.9 | 67.7 | 1046 B | +| Sep_ | SepParserAvx512To256CmpOrMoveMaskTzcnt | Row | 50000 | 3.419 ms | 29 | 8535.4 | 68.4 | 1047 B | +| Sep_ | SepParserVector256NrwCmpExtMsbTzcnt | Row | 50000 | 3.424 ms | 29 | 8521.7 | 68.5 | 1078 B | +| Sep_ | SepParserSse2PackCmpOrMoveMaskTzcnt | Row | 50000 | 3.797 ms | 29 | 7685.3 | 75.9 | 968 B | +| Sep_ | SepParserAvx256To128CmpOrMoveMaskTzcnt | Row | 50000 | 3.815 ms | 29 | 7649.7 | 76.3 | 968 B | +| Sep_ | SepParserAvx512PackCmpOrMoveMaskTzcnt | Row | 50000 | 3.828 ms | 29 | 7623.3 | 76.6 | 1207 B | +| Sep_ | SepParserVector128NrwCmpExtMsbTzcnt | Row | 50000 | 3.852 ms | 29 | 7576.6 | 77.0 | 983 B | +| Sep_ | SepParserVector512NrwCmpExtMsbTzcnt | Row | 50000 | 4.201 ms | 29 | 6946.3 | 84.0 | 1273 B | +| Sep_ | SepParserIndexOfAny | Row | 50000 | 19.134 ms | 29 | 1525.1 | 382.7 | 1002 B | +| Sep_ | SepParserVector64NrwCmpExtMsbTzcnt | Row | 50000 | 143.313 ms | 29 | 203.6 | 2866.3 | 1656 B | diff --git a/benchmarks/AMD.Ryzen.9.9950X/PackageAssetsBench-Parsers.md b/benchmarks/AMD.Ryzen.9.9950X/PackageAssetsBench-Parsers.md new file mode 100644 index 00000000..e9243547 --- /dev/null +++ b/benchmarks/AMD.Ryzen.9.9950X/PackageAssetsBench-Parsers.md @@ -0,0 +1,26 @@ +``` + +BenchmarkDotNet v0.14.0, Windows 10 (10.0.19044.3086/21H2/November2021Update) +AMD Ryzen 9 9950X, 1 CPU, 32 logical and 16 physical cores +.NET SDK 9.0.203 + [Host] : .NET 9.0.4 (9.0.425.16305), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI + Job-HBFNQE : .NET 9.0.4 (9.0.425.16305), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI + +Job=Job-HBFNQE EnvironmentVariables=DOTNET_GCDynamicAdaptationMode=0 Runtime=.NET 9.0 +Toolchain=net90 InvocationCount=Default IterationTime=350ms +MaxIterationCount=15 MinIterationCount=5 WarmupCount=6 +Quotes=False Reader=String + +``` +| Method | Parser | Scope | Rows | Mean | MB | MB/s | ns/row | Allocated | +|------- |--------------------------------------- |------ |------ |----------:|---:|--------:|-------:|----------:| +| Sep_ | SepParserAvx512To256CmpOrMoveMaskTzcnt | Row | 50000 | 1.351 ms | 29 | 21597.7 | 27.0 | 1038 B | +| Sep_ | SepParserVector256NrwCmpExtMsbTzcnt | Row | 50000 | 1.416 ms | 29 | 20608.5 | 28.3 | 1070 B | +| Sep_ | SepParserAvx2PackCmpOrMoveMaskTzcnt | Row | 50000 | 1.417 ms | 29 | 20599.3 | 28.3 | 1038 B | +| Sep_ | SepParserAvx512PackCmpOrMoveMaskTzcnt | Row | 50000 | 1.463 ms | 29 | 19944.3 | 29.3 | 1198 B | +| Sep_ | SepParserAvx256To128CmpOrMoveMaskTzcnt | Row | 50000 | 1.499 ms | 29 | 19465.5 | 30.0 | 958 B | +| Sep_ | SepParserSse2PackCmpOrMoveMaskTzcnt | Row | 50000 | 1.511 ms | 29 | 19312.5 | 30.2 | 958 B | +| Sep_ | SepParserVector128NrwCmpExtMsbTzcnt | Row | 50000 | 1.599 ms | 29 | 18252.1 | 32.0 | 975 B | +| Sep_ | SepParserVector512NrwCmpExtMsbTzcnt | Row | 50000 | 1.615 ms | 29 | 18067.4 | 32.3 | 1262 B | +| Sep_ | SepParserIndexOfAny | Row | 50000 | 10.471 ms | 29 | 2787.0 | 209.4 | 972 B | +| Sep_ | SepParserVector64NrwCmpExtMsbTzcnt | Row | 50000 | 63.446 ms | 29 | 459.9 | 1268.9 | 1280 B | diff --git a/src/Sep.ComparisonBenchmarks/PackageAssetsBench.cs b/src/Sep.ComparisonBenchmarks/PackageAssetsBench.cs index 666b2e3a..f4578911 100644 --- a/src/Sep.ComparisonBenchmarks/PackageAssetsBench.cs +++ b/src/Sep.ComparisonBenchmarks/PackageAssetsBench.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Order; using CsvHelper; using CsvHelper.Configuration; using Sylvan.Data.Csv; @@ -542,3 +543,34 @@ public class GcServerLongAssetPackageAssetsBench : LongAssetPackageAssetsBench [GcServer(true)] public class GcServerLongQuotesAssetPackageAssetsBench : LongQuotesAssetPackageAssetsBench { } + +[BenchmarkCategory("0_Parsers")] +[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByMethod)] +[Orderer(SummaryOrderPolicy.FastestToSlowest)] +public class ParsersRowPackageAssetsBench : PackageAssetsBench +{ + const int DefaultLineCount = 50_000; + + public ParsersRowPackageAssetsBench() : this(false) { } + public ParsersRowPackageAssetsBench(bool quoteAroundSomeCols) : base("Row", DefaultLineCount, quoteAroundSomeCols) { } + + [ParamsSource(nameof(ParserParams))] // Attributes for params is challenging 👇 + public string Parser { get; set; } = SepParserFactory.GetForceParserName(); + public IEnumerable ParserParams() => SepParserFactory.AvailableFactories.Keys; + + [GlobalSetup] + public void GlobalSetup() + { + Environment.SetEnvironmentVariable(SepParserFactory.SepForceParserEnvName, Parser); + var name = SepParserFactory.GetForceParserName(); + Console.WriteLine($"// Using parser: {name}"); + } + + [Benchmark] + public void Sep_() + { + using var reader = Sep.Reader(o => o with { HasHeader = false }) + .From(Reader.CreateReader()); + foreach (var row in reader) { } + } +} diff --git a/src/Sep.ComparisonBenchmarks/Program.cs b/src/Sep.ComparisonBenchmarks/Program.cs index 1359c2bd..2e60aa65 100644 --- a/src/Sep.ComparisonBenchmarks/Program.cs +++ b/src/Sep.ComparisonBenchmarks/Program.cs @@ -70,6 +70,7 @@ { nameof(PackageAssetsBench) + "Quotes", new[] { typeof(QuotesRowPackageAssetsBench), typeof(QuotesColsPackageAssetsBench), typeof(QuotesAssetPackageAssetsBench), typeof(LongQuotesAssetPackageAssetsBench), } }, { nameof(PackageAssetsBench) + "SpacesQuotes", new[] { typeof(SpacesQuotesColsPackageAssetsBench) } }, { nameof(FloatsReaderBench), new[] { typeof(RowFloatsReaderBench), typeof(ColsFloatsReaderBench), typeof(FloatsFloatsReaderBench), } }, + { nameof(PackageAssetsBench) + "-Parsers", new[] { typeof(ParsersRowPackageAssetsBench), } }, }; foreach (var (name, benchTypes) in nameToBenchTypesSet) { diff --git a/src/Sep/Internals/SepParserFactory.cs b/src/Sep/Internals/SepParserFactory.cs index f261da2d..064a79e2 100644 --- a/src/Sep/Internals/SepParserFactory.cs +++ b/src/Sep/Internals/SepParserFactory.cs @@ -10,15 +10,13 @@ namespace nietras.SeparatedValues; static class SepParserFactory { - const string SepForceParserEnvName = "SEPFORCEPARSER"; + internal const string SepForceParserEnvName = "SEPFORCEPARSER"; - static SepParserFactory() - { - CreateBest = CreateBestFunc(); - } + static Func? _createBest = null; [ExcludeFromCodeCoverage] - internal static Func CreateBest { get; } + internal static Func CreateBest => + _createBest ??= CreateBestFunc(); [ExcludeFromCodeCoverage] internal static Func CreateBestFunc()