From 48d9875c2926ea58a825a4ca4e48e2b366f57a7a Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 11 Aug 2023 13:13:26 +0200 Subject: [PATCH 01/30] Add net8.0 target using preview 7 --- global.json | 4 ++-- src/Directory.Build.props | 10 ++++++---- src/Sep.Benchmarks/Sep.Benchmarks.csproj | 1 - .../Sep.ComparisonBenchmarks.csproj | 1 - .../Internals/InterpolatedStringHandlerTest.cs | 1 - src/Sep.Test/Sep.Test.csproj | 1 - src/Sep.Tester/Sep.Tester.csproj | 1 - src/Sep/Internals/SepAssert.cs | 14 ++++++++++---- src/Sep/Internals/SepToStringHashPool.cs | 2 ++ src/Sep/Sep.csproj | 2 +- 10 files changed, 21 insertions(+), 16 deletions(-) diff --git a/global.json b/global.json index ccd059ad..d67aac54 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,7 @@ { "sdk": { - "version": "7.0.200", + "version": "8.0.0", "rollForward": "latestFeature", - "allowPrerelease": false + "allowPrerelease": true } } diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 60492ca9..ea1c71da 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -11,10 +11,7 @@ Copyright © nietras A/S 2023 en - net7.0 - $(TargetFrameworkBase) - $(TargetFrameworkLibrary) - $(TargetFrameworkLibrary) + net7.0;net8.0 11.0 true @@ -24,11 +21,16 @@ true true + + true + $(NoWarn);CS1591 + latest true true true true + true $(DefineConstants);SEPBENCHSLOWONES $(DefineConstants);SEPASSERT diff --git a/src/Sep.Benchmarks/Sep.Benchmarks.csproj b/src/Sep.Benchmarks/Sep.Benchmarks.csproj index 498a5156..936f1750 100644 --- a/src/Sep.Benchmarks/Sep.Benchmarks.csproj +++ b/src/Sep.Benchmarks/Sep.Benchmarks.csproj @@ -1,7 +1,6 @@  - $(TargetFrameworkConsole) nietras.SeparatedValues.Benchmarks Exe diff --git a/src/Sep.ComparisonBenchmarks/Sep.ComparisonBenchmarks.csproj b/src/Sep.ComparisonBenchmarks/Sep.ComparisonBenchmarks.csproj index b2f26de9..ed486094 100644 --- a/src/Sep.ComparisonBenchmarks/Sep.ComparisonBenchmarks.csproj +++ b/src/Sep.ComparisonBenchmarks/Sep.ComparisonBenchmarks.csproj @@ -1,7 +1,6 @@  - $(TargetFrameworkConsole) nietras.SeparatedValues.Benchmarks Exe diff --git a/src/Sep.Test/Internals/InterpolatedStringHandlerTest.cs b/src/Sep.Test/Internals/InterpolatedStringHandlerTest.cs index df7858ea..de4ab5c5 100644 --- a/src/Sep.Test/Internals/InterpolatedStringHandlerTest.cs +++ b/src/Sep.Test/Internals/InterpolatedStringHandlerTest.cs @@ -83,7 +83,6 @@ public void AppendFormatted(T t) internal string GetFormattedText() => builder.ToString(); } - /// Provides a handler used by the language compiler to append interpolated strings into instances. [EditorBrowsable(EditorBrowsableState.Never)] [InterpolatedStringHandler] public readonly struct FormatInterpolatedStringHandler diff --git a/src/Sep.Test/Sep.Test.csproj b/src/Sep.Test/Sep.Test.csproj index 8e7d0508..eb8bceba 100644 --- a/src/Sep.Test/Sep.Test.csproj +++ b/src/Sep.Test/Sep.Test.csproj @@ -1,7 +1,6 @@  - $(TargetFrameworkLibraryTest) nietras.SeparatedValues.Test true false diff --git a/src/Sep.Tester/Sep.Tester.csproj b/src/Sep.Tester/Sep.Tester.csproj index 1e646df5..7619b1a1 100644 --- a/src/Sep.Tester/Sep.Tester.csproj +++ b/src/Sep.Tester/Sep.Tester.csproj @@ -1,7 +1,6 @@  - $(TargetFrameworkConsole) nietras.SeparatedValues.Tester Exe true diff --git a/src/Sep/Internals/SepAssert.cs b/src/Sep/Internals/SepAssert.cs index 2fcaf478..5482e792 100644 --- a/src/Sep/Internals/SepAssert.cs +++ b/src/Sep/Internals/SepAssert.cs @@ -9,9 +9,10 @@ namespace nietras.SeparatedValues; /// -/// Many unit test frameworks do not handle -/// very well including MSTest, so instead defining some custom assert code that -/// throws an ordinary exception instead and provides some more details. +/// Many unit test frameworks do not handle very well including MSTest, +/// so instead defining some custom assert code that throws an ordinary +/// exception instead and provides some more details. /// [ExcludeFromCodeCoverage] static class SepAssert @@ -65,7 +66,12 @@ internal static void Throw_InvalidOperationException_Assert(string message) throw new InvalidOperationException(message); } - /// Provides an interpolated string handler for that only performs formatting if the assert fails. + /// + /// Provides an interpolated string handler for that only performs formatting if the assert + /// fails. + /// [EditorBrowsable(EditorBrowsableState.Never)] [InterpolatedStringHandler] internal struct AssertInterpolatedStringHandler diff --git a/src/Sep/Internals/SepToStringHashPool.cs b/src/Sep/Internals/SepToStringHashPool.cs index 4c880f1e..275d654b 100644 --- a/src/Sep/Internals/SepToStringHashPool.cs +++ b/src/Sep/Internals/SepToStringHashPool.cs @@ -44,6 +44,8 @@ struct Entry /// Simple string pool based on a very simple, fast, but poor hash. /// /// The string length beyond which strings will not be pooled. + /// Initial requested capacity of pool. May be rounded up to nearest power of two. + /// Maximum capacity of pool. If pool full all new spans result in new strings. /// /// The prevents pooling strings beyond a certain length. /// Longer strings are typically less likely to be duplicated, and carry extra cost for identifying uniqueness. diff --git a/src/Sep/Sep.csproj b/src/Sep/Sep.csproj index b15bed10..e89a0837 100644 --- a/src/Sep/Sep.csproj +++ b/src/Sep/Sep.csproj @@ -1,7 +1,6 @@  - $(TargetFrameworkLibrary) nietras.SeparatedValues true true @@ -11,6 +10,7 @@ Modern, minimal, fast, zero allocation, reading and writing of separated values (csv, tsv etc.). Cross-platform, trimmable and AOT/NativeAOT compatible. + Sep csv;csvhelper;comma;semi-colon;tab;separated;value;delimited;io;file;read;write;parse;format From 7fad2143dab884d6b7c03af4aecd9319f2bf891b Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 11 Aug 2023 13:31:11 +0200 Subject: [PATCH 02/30] Add SepParserVector512NrwCmpExtMsbTzcnt and refactor mask to use nuint etc. --- .../SepParseSeparatorsMaskBench.cs | 4 +- src/Sep.Test/SepParseMaskTest.cs | 6 +- .../SepParseMaskTest_ParseAnyCharsMask.cs | 2 +- ...askTest_ParseSeparatorsLineEndingsMasks.cs | 10 +- .../SepParseMaskTest_ParseSeparatorsMask.cs | 8 +- src/Sep/Internals/SepParseMask.cs | 16 +- .../SepParserAvx2PackCmpOrMoveMaskTzcnt.cs | 8 +- src/Sep/Internals/SepParserFactory.cs | 7 + src/Sep/Internals/SepParserIndexOfAny.cs | 2 +- .../SepParserSse2PackCmpOrMoveMaskTzcnt.cs | 8 +- .../SepParserVector128NrwCmpExtMsbTzcnt.cs | 8 +- .../SepParserVector256NrwCmpExtMsbTzcnt.cs | 8 +- .../SepParserVector512NrwCmpExtMsbTzcnt.cs | 148 ++++++++++++++++++ .../SepParserVector64NrwCmpExtMsbTzcnt.cs | 8 +- 14 files changed, 199 insertions(+), 44 deletions(-) create mode 100644 src/Sep/Internals/SepParserVector512NrwCmpExtMsbTzcnt.cs diff --git a/src/Sep.Benchmarks/SepParseSeparatorsMaskBench.cs b/src/Sep.Benchmarks/SepParseSeparatorsMaskBench.cs index ab3ba5cf..b6649dbf 100644 --- a/src/Sep.Benchmarks/SepParseSeparatorsMaskBench.cs +++ b/src/Sep.Benchmarks/SepParseSeparatorsMaskBench.cs @@ -8,14 +8,14 @@ namespace nietras.SeparatedValues.Benchmarks; public unsafe class SepParseSeparatorsMaskBench { - public readonly record struct MaskSpec(int Mask) + public readonly record struct MaskSpec(uint Mask) { public override string ToString() => Convert.ToString(Mask, 2).PadLeft(32, '0'); } readonly MaskSpec[] _masks; MaskSpec _mask; - int _maskValue; + uint _maskValue; readonly int _dataIndex = 17; readonly int* _colEnds = (int*)NativeMemory.Alloc(32, sizeof(int)); diff --git a/src/Sep.Test/SepParseMaskTest.cs b/src/Sep.Test/SepParseMaskTest.cs index 6a342c0e..2509c853 100644 --- a/src/Sep.Test/SepParseMaskTest.cs +++ b/src/Sep.Test/SepParseMaskTest.cs @@ -11,7 +11,7 @@ public partial class SepParseMaskTest const char Separator = ';'; const int CharsIndexOffset = 17; - static int MaskFor(ReadOnlySpan chars) + static uint MaskFor(ReadOnlySpan chars) { var mask = 0; for (var i = 0; i < Math.Min(chars.Length, 32); i++) @@ -21,7 +21,7 @@ static int MaskFor(ReadOnlySpan chars) mask |= 1 << i; } } - return mask; + return (uint)mask; } static bool IsSpecialChar(char c) => c switch @@ -36,7 +36,7 @@ static int MaskFor(ReadOnlySpan chars) static void AssertParseState(int[] expected, Span colEnds, ref int start, ref int end, int expectedRowLineEndingOffset, int rowLineEndingOffset, - int expectedQuoting, int quoting, + nuint expectedQuoting, nuint quoting, int expectedLineNumber, int lineNumber) { var count = (int)Unsafe.ByteOffset(ref start, ref end) / sizeof(int); diff --git a/src/Sep.Test/SepParseMaskTest_ParseAnyCharsMask.cs b/src/Sep.Test/SepParseMaskTest_ParseAnyCharsMask.cs index d03d0d7f..67146ca3 100644 --- a/src/Sep.Test/SepParseMaskTest_ParseAnyCharsMask.cs +++ b/src/Sep.Test/SepParseMaskTest_ParseAnyCharsMask.cs @@ -57,7 +57,7 @@ public void SepParseMaskTest_ParseAnyCharsMask_Quotes() static void AssertParseAnyCharsMask(string chars, int[] expected, int rowLineEndingOffset, int expectedRowLineEndingOffset, - int quoting = 0, int expectedQuoting = 0, + nuint quoting = 0, nuint expectedQuoting = 0, int lineNumber = -1, int expectedLineNumber = -1) { for (var i = 0; i < expected.Length; ++i) { expected[i] += CharsIndexOffset; } diff --git a/src/Sep.Test/SepParseMaskTest_ParseSeparatorsLineEndingsMasks.cs b/src/Sep.Test/SepParseMaskTest_ParseSeparatorsLineEndingsMasks.cs index ece5cfa3..aa7c6399 100644 --- a/src/Sep.Test/SepParseMaskTest_ParseSeparatorsLineEndingsMasks.cs +++ b/src/Sep.Test/SepParseMaskTest_ParseSeparatorsLineEndingsMasks.cs @@ -33,7 +33,7 @@ public void SepParseMaskTest_ParseSeparatorsLineEndingsMasks_Ordinary() static void AssertParseSeparatorsLineEndingsMasks(string chars, int[] expected, int rowLineEndingOffset, int expectedRowLineEndingOffset, - int quoting = 0, int expectedQuoting = 0, + nuint quoting = 0, nuint expectedQuoting = 0, int lineNumber = -1, int expectedLineNumber = -1) { for (var i = 0; i < expected.Length; ++i) { expected[i] += CharsIndexOffset; } @@ -55,7 +55,7 @@ ref MemoryMarshal.GetReference(chars), ref charsIndex, Separator, expectedLineNumber, lineNumber); } - static int SeparatorsMaskFor(ReadOnlySpan chars) + static uint SeparatorsMaskFor(ReadOnlySpan chars) { var mask = 0; for (var i = 0; i < Math.Min(chars.Length, 32); i++) @@ -65,10 +65,10 @@ static int SeparatorsMaskFor(ReadOnlySpan chars) mask |= 1 << i; } } - return mask; + return (uint)mask; } - static int LineEndingsMaskFor(ReadOnlySpan chars) + static uint LineEndingsMaskFor(ReadOnlySpan chars) { var mask = 0; for (var i = 0; i < Math.Min(chars.Length, 32); i++) @@ -79,6 +79,6 @@ static int LineEndingsMaskFor(ReadOnlySpan chars) mask |= 1 << i; } } - return mask; + return (uint)mask; } } diff --git a/src/Sep.Test/SepParseMaskTest_ParseSeparatorsMask.cs b/src/Sep.Test/SepParseMaskTest_ParseSeparatorsMask.cs index 20e973eb..605a8e0b 100644 --- a/src/Sep.Test/SepParseMaskTest_ParseSeparatorsMask.cs +++ b/src/Sep.Test/SepParseMaskTest_ParseSeparatorsMask.cs @@ -10,16 +10,16 @@ namespace nietras.SeparatedValues.Test; public partial class SepParseMaskTest { - sealed record Data(int Mask, int[] Expected); + sealed record Data(uint Mask, int[] Expected); public delegate ref int ParseSeparatorsMaskMethod( - int mask, int charsIndex, ref int colEndsRef); + nuint mask, int charsIndex, ref int colEndsRef); static readonly Data[] s_data = new Data[] { new(0b0000_0000_0100_0001, new[] { 0, 6, }), new(0b1000_1001_0100_0001, new[] { 0, 6, 8, 11, 15 }), - new(-1, Enumerable.Range(0, 32).ToArray()), + new(uint.MaxValue, Enumerable.Range(0, 32).ToArray()), // Empty mask will output index after mask, that is expected, check mask // before calling parse mask. Some methods will not do the same since // using PopCount. @@ -44,7 +44,7 @@ public void SepParseMaskTest_ParseSeparatorsMask_Test_(ParseSeparatorsMaskMethod } static void AssertParseSeparatorsMask( - int mask, ParseSeparatorsMaskMethod parse, int[] expected) + nuint mask, ParseSeparatorsMaskMethod parse, int[] expected) { Span colEnds = stackalloc int[32 + 1]; ref var start = ref MemoryMarshal.GetReference(colEnds); diff --git a/src/Sep/Internals/SepParseMask.cs b/src/Sep/Internals/SepParseMask.cs index 38df999b..78580bf4 100644 --- a/src/Sep/Internals/SepParseMask.cs +++ b/src/Sep/Internals/SepParseMask.cs @@ -8,7 +8,7 @@ namespace nietras.SeparatedValues; static class SepParseMask { [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static ref int ParseSeparatorsMask(int mask, int charsIndex, ref int colEndsRef) + internal static ref int ParseSeparatorsMask(nuint mask, int charsIndex, ref int colEndsRef) { do { @@ -24,7 +24,7 @@ internal static ref int ParseSeparatorsMask(int mask, int charsIndex, ref int co // Not faster [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static ref int ParseSeparatorsMaskLong(int mask, int charsIndex, ref int positionsRefCurrent) + internal static ref int ParseSeparatorsMaskLong(nuint mask, int charsIndex, ref int positionsRefCurrent) { var count = BitOperations.PopCount((uint)mask); ref var positionsRefCurrentEnd = ref Add(ref positionsRefCurrent, count); @@ -49,9 +49,9 @@ internal static ref int ParseSeparatorsMaskLong(int mask, int charsIndex, ref in } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static ref int ParseAnyCharsMask(int mask, char separator, + internal static ref int ParseAnyCharsMask(nuint mask, char separator, scoped ref char charsRef, int charsIndex, - scoped ref int rowLineEndingOffset, scoped ref int quoting, + scoped ref int rowLineEndingOffset, scoped ref nuint quoting, ref int colEndsRef, scoped ref int lineNumber) { do @@ -71,7 +71,7 @@ internal static ref int ParseAnyCharsMask(int mask, char separator, [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static ref int ParseAnyChar( scoped ref char charsRef, int charsIndex, int relativeIndex, char separator, - scoped ref int rowLineEndingOffset, scoped ref int quoting, + scoped ref int rowLineEndingOffset, scoped ref nuint quoting, ref int colEndsRef, scoped ref int lineNumber) { var c = Add(ref charsRef, relativeIndex); @@ -123,7 +123,7 @@ internal static ref int ParseAnyChar( } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static ref int ParseSeparatorsLineEndingsMasks(int separatorsMask, int separatorsLineEndingsMask, + internal static ref int ParseSeparatorsLineEndingsMasks(nuint separatorsMask, nuint separatorsLineEndingsMask, scoped ref char charsRef, scoped ref int charsIndex, char separator, ref int colEndsRefCurrent, scoped ref int rowLineEndingOffset, scoped ref int lineNumber) { @@ -173,7 +173,7 @@ internal static ref int ParseSeparatorsLineEndingsMasks(int separatorsMask, int } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static ref int ParseLineEndingMask(int lineEndingsMask, + internal static ref int ParseLineEndingMask(nuint lineEndingsMask, scoped ref char charsRef, scoped ref int charsIndex, ref int colEndsRefCurrent, scoped ref int rowLineEndingOffset, scoped ref int lineNumber) { @@ -195,7 +195,7 @@ internal static ref int ParseLineEndingMask(int lineEndingsMask, } [MethodImpl(MethodImplOptions.AggressiveInlining)] - static ref int ParseSeparatorsLineEndingsMask(int mask, char separator, + static ref int ParseSeparatorsLineEndingsMask(nuint mask, char separator, scoped ref char charsRef, int charsIndex, scoped ref int rowLineEndingOffset, ref int colEndsRef, scoped ref int lineNumber) diff --git a/src/Sep/Internals/SepParserAvx2PackCmpOrMoveMaskTzcnt.cs b/src/Sep/Internals/SepParserAvx2PackCmpOrMoveMaskTzcnt.cs index b8e1eeff..79058d6c 100644 --- a/src/Sep/Internals/SepParserAvx2PackCmpOrMoveMaskTzcnt.cs +++ b/src/Sep/Internals/SepParserAvx2PackCmpOrMoveMaskTzcnt.cs @@ -19,7 +19,7 @@ sealed class SepParserAvx2PackCmpOrMoveMaskTzcnt : ISepParser readonly VecUI8 _crs = Vec.Create(CarriageReturnByte); readonly VecUI8 _qts = Vec.Create(QuoteByte); readonly VecUI8 _sps; - internal int _quoting = 0; + internal nuint _quoting = 0; public unsafe SepParserAvx2PackCmpOrMoveMaskTzcnt(Sep sep) { @@ -81,10 +81,10 @@ public int Parse(char[] chars, int charsIndex, int charsEnd, var specialChars = lineEndingsSeparators | qtsEq; // Optimize for the case of no special character - var specialCharMask = ISA.MoveMask(specialChars); + var specialCharMask = (uint)ISA.MoveMask(specialChars); if (specialCharMask != 0) { - var separatorsMask = ISA.MoveMask(spsEq); + var separatorsMask = (uint)ISA.MoveMask(spsEq); // Optimize for case of only separators i.e. no endings or quotes. // Add quoting flags to mask as hack to skip if quoting. var testMask = specialCharMask + quoting; @@ -95,7 +95,7 @@ public int Parse(char[] chars, int charsIndex, int charsEnd, } else { - var separatorLineEndingsMask = ISA.MoveMask(lineEndingsSeparators); + var separatorLineEndingsMask = (uint)ISA.MoveMask(lineEndingsSeparators); if (separatorLineEndingsMask == testMask) { colEndsRefCurrent = ref ParseSeparatorsLineEndingsMasks( diff --git a/src/Sep/Internals/SepParserFactory.cs b/src/Sep/Internals/SepParserFactory.cs index 063ef85f..6c9c8edc 100644 --- a/src/Sep/Internals/SepParserFactory.cs +++ b/src/Sep/Internals/SepParserFactory.cs @@ -11,6 +11,9 @@ static class SepParserFactory [ExcludeFromCodeCoverage] internal static ISepParser CreateBest(Sep sep) { +#if NET8_0_OR_GREATER + if (Vector512.IsHardwareAccelerated) { return new SepParserVector512NrwCmpExtMsbTzcnt(sep); } +#endif if (Avx2.IsSupported) { return new SepParserAvx2PackCmpOrMoveMaskTzcnt(sep); } if (Sse2.IsSupported) { return new SepParserSse2PackCmpOrMoveMaskTzcnt(sep); } if (Vector256.IsHardwareAccelerated) { return new SepParserVector256NrwCmpExtMsbTzcnt(sep); } @@ -25,6 +28,10 @@ internal static IReadOnlyDictionary> CreateAccelerat internal static IReadOnlyDictionary> CreateFactories(bool createUnaccelerated = true) { var parsers = new Dictionary>(); +#if NET8_0_OR_GREATER + if (Vector512.IsHardwareAccelerated) + { Add(parsers, static sep => new SepParserVector512NrwCmpExtMsbTzcnt(sep)); } +#endif if (Avx2.IsSupported) { Add(parsers, static sep => new SepParserAvx2PackCmpOrMoveMaskTzcnt(sep)); } if (Sse2.IsSupported) diff --git a/src/Sep/Internals/SepParserIndexOfAny.cs b/src/Sep/Internals/SepParserIndexOfAny.cs index 7072a4be..3d785ce8 100644 --- a/src/Sep/Internals/SepParserIndexOfAny.cs +++ b/src/Sep/Internals/SepParserIndexOfAny.cs @@ -10,7 +10,7 @@ sealed class SepParserIndexOfAny : ISepParser { readonly char _separator; readonly char[] _specialChars; - int _quoting = 0; + nuint _quoting = 0; public unsafe SepParserIndexOfAny(Sep sep) { diff --git a/src/Sep/Internals/SepParserSse2PackCmpOrMoveMaskTzcnt.cs b/src/Sep/Internals/SepParserSse2PackCmpOrMoveMaskTzcnt.cs index b96332ba..9bcc344d 100644 --- a/src/Sep/Internals/SepParserSse2PackCmpOrMoveMaskTzcnt.cs +++ b/src/Sep/Internals/SepParserSse2PackCmpOrMoveMaskTzcnt.cs @@ -18,7 +18,7 @@ sealed class SepParserSse2PackCmpOrMoveMaskTzcnt : ISepParser readonly VecUI8 _crs = Vec.Create(CarriageReturnByte); readonly VecUI8 _qts = Vec.Create(QuoteByte); readonly VecUI8 _sps; - internal int _quoting = 0; + internal nuint _quoting = 0; public unsafe SepParserSse2PackCmpOrMoveMaskTzcnt(Sep sep) { @@ -78,10 +78,10 @@ public int Parse(char[] chars, int charsIndex, int charsEnd, var specialChars = lineEndingsSeparators | qtsEq; // Optimize for the case of no special character - var specialCharMask = ISA.MoveMask(specialChars); + var specialCharMask = (uint)ISA.MoveMask(specialChars); if (specialCharMask != 0) { - var separatorsMask = ISA.MoveMask(spsEq); + var separatorsMask = (uint)ISA.MoveMask(spsEq); // Optimize for case of only separators i.e. no endings or quotes. // Add quoting flags to mask as hack to skip if quoting. var testMask = specialCharMask + quoting; @@ -92,7 +92,7 @@ public int Parse(char[] chars, int charsIndex, int charsEnd, } else { - var separatorLineEndingsMask = ISA.MoveMask(lineEndingsSeparators); + var separatorLineEndingsMask = (uint)ISA.MoveMask(lineEndingsSeparators); if (separatorLineEndingsMask == testMask) { colEndsRefCurrent = ref ParseSeparatorsLineEndingsMasks( diff --git a/src/Sep/Internals/SepParserVector128NrwCmpExtMsbTzcnt.cs b/src/Sep/Internals/SepParserVector128NrwCmpExtMsbTzcnt.cs index 9800c065..876fc247 100644 --- a/src/Sep/Internals/SepParserVector128NrwCmpExtMsbTzcnt.cs +++ b/src/Sep/Internals/SepParserVector128NrwCmpExtMsbTzcnt.cs @@ -19,7 +19,7 @@ sealed class SepParserVector128NrwCmpExtMsbTzcnt : ISepParser readonly VecUI8 _crs = Vec.Create(CarriageReturnByte); readonly VecUI8 _qts = Vec.Create(QuoteByte); readonly VecUI8 _sps; - internal int _quoting = 0; + internal nuint _quoting = 0; public unsafe SepParserVector128NrwCmpExtMsbTzcnt(Sep sep) { @@ -82,10 +82,10 @@ public int Parse(char[] chars, int charsIndex, int charsEnd, var specialChars = lineEndingsSeparators | qtsEq; // Optimize for the case of no special character - var specialCharMask = (int)specialChars.ExtractMostSignificantBits(); + var specialCharMask = specialChars.ExtractMostSignificantBits(); if (specialCharMask != 0) { - var separatorsMask = (int)spsEq.ExtractMostSignificantBits(); + var separatorsMask = spsEq.ExtractMostSignificantBits(); // Optimize for case of only separators i.e. no endings or quotes. // Add quoting flags to mask as hack to skip if quoting. var testMask = specialCharMask + quoting; @@ -96,7 +96,7 @@ public int Parse(char[] chars, int charsIndex, int charsEnd, } else { - var separatorLineEndingsMask = (int)lineEndingsSeparators.ExtractMostSignificantBits(); + var separatorLineEndingsMask = lineEndingsSeparators.ExtractMostSignificantBits(); if (separatorLineEndingsMask == testMask) { colEndsRefCurrent = ref ParseSeparatorsLineEndingsMasks( diff --git a/src/Sep/Internals/SepParserVector256NrwCmpExtMsbTzcnt.cs b/src/Sep/Internals/SepParserVector256NrwCmpExtMsbTzcnt.cs index a38c3cf6..6cfd1a4d 100644 --- a/src/Sep/Internals/SepParserVector256NrwCmpExtMsbTzcnt.cs +++ b/src/Sep/Internals/SepParserVector256NrwCmpExtMsbTzcnt.cs @@ -19,7 +19,7 @@ sealed class SepParserVector256NrwCmpExtMsbTzcnt : ISepParser readonly VecUI8 _crs = Vec.Create(CarriageReturnByte); readonly VecUI8 _qts = Vec.Create(QuoteByte); readonly VecUI8 _sps; - internal int _quoting = 0; + internal nuint _quoting = 0; public unsafe SepParserVector256NrwCmpExtMsbTzcnt(Sep sep) { @@ -82,10 +82,10 @@ public int Parse(char[] chars, int charsIndex, int charsEnd, var specialChars = lineEndingsSeparators | qtsEq; // Optimize for the case of no special character - var specialCharMask = (int)specialChars.ExtractMostSignificantBits(); + var specialCharMask = specialChars.ExtractMostSignificantBits(); if (specialCharMask != 0) { - var separatorsMask = (int)spsEq.ExtractMostSignificantBits(); + var separatorsMask = spsEq.ExtractMostSignificantBits(); // Optimize for case of only separators i.e. no endings or quotes. // Add quoting flags to mask as hack to skip if quoting. var testMask = specialCharMask + quoting; @@ -96,7 +96,7 @@ public int Parse(char[] chars, int charsIndex, int charsEnd, } else { - var separatorLineEndingsMask = (int)lineEndingsSeparators.ExtractMostSignificantBits(); + var separatorLineEndingsMask = lineEndingsSeparators.ExtractMostSignificantBits(); if (separatorLineEndingsMask == testMask) { colEndsRefCurrent = ref ParseSeparatorsLineEndingsMasks( diff --git a/src/Sep/Internals/SepParserVector512NrwCmpExtMsbTzcnt.cs b/src/Sep/Internals/SepParserVector512NrwCmpExtMsbTzcnt.cs new file mode 100644 index 00000000..802d4fc8 --- /dev/null +++ b/src/Sep/Internals/SepParserVector512NrwCmpExtMsbTzcnt.cs @@ -0,0 +1,148 @@ +#if NET8_0_OR_GREATER +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using static System.Runtime.CompilerServices.Unsafe; +using static nietras.SeparatedValues.SepDefaults; +using static nietras.SeparatedValues.SepParseMask; +using Vec = System.Runtime.Intrinsics.Vector512; +using VecUI16 = System.Runtime.Intrinsics.Vector512; +using VecUI8 = System.Runtime.Intrinsics.Vector512; + +namespace nietras.SeparatedValues; + +sealed class SepParserVector512NrwCmpExtMsbTzcnt : ISepParser +{ + readonly byte _separator; + readonly VecUI16 _max = Vec.Create((ushort)(Sep.Max.Separator + 1)); + readonly VecUI8 _nls = Vec.Create(LineFeedByte); + readonly VecUI8 _crs = Vec.Create(CarriageReturnByte); + readonly VecUI8 _qts = Vec.Create(QuoteByte); + readonly VecUI8 _sps; + internal nuint _quoting = 0; + + public unsafe SepParserVector512NrwCmpExtMsbTzcnt(Sep sep) + { + A.Assert(Environment.Is64BitProcess); + _separator = (byte)sep.Separator; + _sps = Vec.Create(_separator); + } + + // Parses 2 x char vectors e.g. 1 byte vector + public int PaddingLength => VecUI8.Count; + + [SkipLocalsInit] + public int Parse(char[] chars, int charsIndex, int charsEnd, + int[] colEnds, ref int colEndsEnd, + scoped ref int _rowLineEndingOffset, scoped ref int _lineNumber) + { + // Method should **not** call other non-inlined methods, since this + // impacts code-generation severely. + + var separator = (char)_separator; + + var quoting = _quoting; + var rowLineEndingOffset = _rowLineEndingOffset; + var lineNumber = _lineNumber; + + chars.CheckPaddingAndIsZero(charsEnd, PaddingLength); + colEnds.CheckPadding(colEndsEnd, PaddingLength); + + A.Assert(charsIndex <= charsEnd); + A.Assert(charsEnd <= (chars.Length - PaddingLength)); + ref var charsRef = ref Add(ref MemoryMarshal.GetArrayDataReference(chars), charsIndex); + + ref var colEndsRef = ref MemoryMarshal.GetArrayDataReference(colEnds); + ref var colEndsRefCurrent = ref Add(ref colEndsRef, colEndsEnd); + ref var colEndsRefStop = ref Add(ref colEndsRef, colEnds.Length - VecUI8.Count); + + // Use instance fields to force values into registers + var max = _max; + var nls = _nls; //Vec.Create(LineFeedByte); + var crs = _crs; //Vec.Create(CarriageReturnByte); + var qts = _qts; //Vec.Create(QuoteByte); + var sps = _sps; //Vec.Create(_separator); + + for (; charsIndex < charsEnd; charsIndex += VecUI8.Count, + charsRef = ref Add(ref charsRef, VecUI8.Count)) + { + ref var byteRef = ref As(ref charsRef); + var v0 = ReadUnaligned(ref byteRef); + var v1 = ReadUnaligned(ref Add(ref byteRef, VecUI8.Count)); + var limit0 = Vec.Min(v0, max); + var limit1 = Vec.Min(v1, max); + var bytes = Vec.Narrow(limit0, limit1); + + var nlsEq = Vec.Equals(bytes, nls); + var crsEq = Vec.Equals(bytes, crs); + var qtsEq = Vec.Equals(bytes, qts); + var spsEq = Vec.Equals(bytes, sps); + + var lineEndings = nlsEq | crsEq; + var lineEndingsSeparators = spsEq | lineEndings; + var specialChars = lineEndingsSeparators | qtsEq; + + // Optimize for the case of no special character + var specialCharMask = (nuint)specialChars.ExtractMostSignificantBits(); + if (specialCharMask != 0) + { + var separatorsMask = (nuint)spsEq.ExtractMostSignificantBits(); + // Optimize for case of only separators i.e. no endings or quotes. + // Add quoting flags to mask as hack to skip if quoting. + var testMask = specialCharMask + quoting; + if (separatorsMask == testMask) + { + colEndsRefCurrent = ref ParseSeparatorsMask(separatorsMask, charsIndex, + ref colEndsRefCurrent); + } + else + { + var separatorLineEndingsMask = (nuint)lineEndingsSeparators.ExtractMostSignificantBits(); + if (separatorLineEndingsMask == testMask) + { + colEndsRefCurrent = ref ParseSeparatorsLineEndingsMasks( + separatorsMask, separatorLineEndingsMask, + ref charsRef, ref charsIndex, separator, + ref colEndsRefCurrent, ref rowLineEndingOffset, ref lineNumber); + break; + } + else + { + colEndsRefCurrent = ref ParseAnyCharsMask(specialCharMask, + separator, ref charsRef, charsIndex, + ref rowLineEndingOffset, ref quoting, + ref colEndsRefCurrent, ref lineNumber); + // Used both to indicate row ended and if need to step +2 due to '\r\n' + if (rowLineEndingOffset != 0) + { + // Must be a col end and last is then dataIndex + charsIndex = colEndsRefCurrent + rowLineEndingOffset; + break; + } + } + } + // If current is greater than or equal than "stop", then break. + // There is no longer guaranteed space enough for next VecUI8.Count. + if (IsAddressLessThan(ref colEndsRefStop, ref colEndsRefCurrent)) + { + // Move data index so next find starts correctly + charsIndex += VecUI8.Count; + break; + } + } + } + + // ">> 2" instead of "/ sizeof(int))" // CQ: Weird with div sizeof + colEndsEnd = (int)(ByteOffset(ref colEndsRef, ref colEndsRefCurrent) >> 2); + // Step is VecUI8.Count so may go past end, ensure limited + charsIndex = Math.Min(charsEnd, charsIndex); + + _quoting = quoting; + _rowLineEndingOffset = rowLineEndingOffset; + _lineNumber = lineNumber; + + return charsIndex; + } +} +#endif diff --git a/src/Sep/Internals/SepParserVector64NrwCmpExtMsbTzcnt.cs b/src/Sep/Internals/SepParserVector64NrwCmpExtMsbTzcnt.cs index 04df41b3..0a595ce2 100644 --- a/src/Sep/Internals/SepParserVector64NrwCmpExtMsbTzcnt.cs +++ b/src/Sep/Internals/SepParserVector64NrwCmpExtMsbTzcnt.cs @@ -19,7 +19,7 @@ sealed class SepParserVector64NrwCmpExtMsbTzcnt : ISepParser readonly VecUI8 _crs = Vec.Create(CarriageReturnByte); readonly VecUI8 _qts = Vec.Create(QuoteByte); readonly VecUI8 _sps; - internal int _quoting = 0; + internal nuint _quoting = 0; public unsafe SepParserVector64NrwCmpExtMsbTzcnt(Sep sep) { @@ -82,10 +82,10 @@ public int Parse(char[] chars, int charsIndex, int charsEnd, var specialChars = lineEndingsSeparators | qtsEq; // Optimize for the case of no special character - var specialCharMask = (int)specialChars.ExtractMostSignificantBits(); + var specialCharMask = specialChars.ExtractMostSignificantBits(); if (specialCharMask != 0) { - var separatorsMask = (int)spsEq.ExtractMostSignificantBits(); + var separatorsMask = spsEq.ExtractMostSignificantBits(); // Optimize for case of only separators i.e. no endings or quotes. // Add quoting flags to mask as hack to skip if quoting. var testMask = specialCharMask + quoting; @@ -96,7 +96,7 @@ public int Parse(char[] chars, int charsIndex, int charsEnd, } else { - var separatorLineEndingsMask = (int)lineEndingsSeparators.ExtractMostSignificantBits(); + var separatorLineEndingsMask = lineEndingsSeparators.ExtractMostSignificantBits(); if (separatorLineEndingsMask == testMask) { colEndsRefCurrent = ref ParseSeparatorsLineEndingsMasks( From dbe9a0a2da52d5d9ec0da58779404c649d45d2d4 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 11 Aug 2023 13:35:18 +0200 Subject: [PATCH 03/30] try to quick fix padding so 64 for AVX-512 --- src/Sep/SepReader.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Sep/SepReader.cs b/src/Sep/SepReader.cs index 5dee82c0..7fad6ce5 100644 --- a/src/Sep/SepReader.cs +++ b/src/Sep/SepReader.cs @@ -34,7 +34,7 @@ public partial class SepReader : IDisposable #if DEBUG // To increase probability of detecting bugs start with short length to // force chars buffer management paths to be used. - internal const int CharsMinimumLength = 32; + internal const int CharsMinimumLength = 64; #else // Based on L1d typically being 32KB-48KB, so aiming for 16K-24K x sizeof(char). // Benchmarks show below to be a good minimum length. @@ -93,11 +93,11 @@ internal SepReader(SepReaderOptions options, TextReader reader) } else { - _charsPaddingLength = 32; + _charsPaddingLength = 64; _charsMinimumFreeLength = Math.Max(_chars.Length / 2, _charsPaddingLength); } - var paddingLength = _parser?.PaddingLength ?? 32; + var paddingLength = _parser?.PaddingLength ?? 64; _colEnds = ArrayPool.Shared.Rent(Math.Max(_colEndsMaximumLength, paddingLength * 2)); From 8ded033610246831fcaafc457b7556fc1367a8f9 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 11 Aug 2023 13:44:36 +0200 Subject: [PATCH 04/30] try to force AVX-512 used on i7-9800X --- src/Sep/Internals/SepParserFactory.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Sep/Internals/SepParserFactory.cs b/src/Sep/Internals/SepParserFactory.cs index 6c9c8edc..ca1f0c9f 100644 --- a/src/Sep/Internals/SepParserFactory.cs +++ b/src/Sep/Internals/SepParserFactory.cs @@ -12,7 +12,7 @@ static class SepParserFactory internal static ISepParser CreateBest(Sep sep) { #if NET8_0_OR_GREATER - if (Vector512.IsHardwareAccelerated) { return new SepParserVector512NrwCmpExtMsbTzcnt(sep); } + if (Avx512F.IsSupported) { return new SepParserVector512NrwCmpExtMsbTzcnt(sep); } #endif if (Avx2.IsSupported) { return new SepParserAvx2PackCmpOrMoveMaskTzcnt(sep); } if (Sse2.IsSupported) { return new SepParserSse2PackCmpOrMoveMaskTzcnt(sep); } @@ -29,7 +29,7 @@ internal static IReadOnlyDictionary> CreateFactories { var parsers = new Dictionary>(); #if NET8_0_OR_GREATER - if (Vector512.IsHardwareAccelerated) + if (Avx512F.IsSupported) //Vector512.IsHardwareAccelerated) { Add(parsers, static sep => new SepParserVector512NrwCmpExtMsbTzcnt(sep)); } #endif if (Avx2.IsSupported) From 0ba6174d81ee192c77bc17df0de8462553aa990a Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 11 Aug 2023 13:48:36 +0200 Subject: [PATCH 05/30] improve assert message --- src/Sep.Test/SepParserTest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Sep.Test/SepParserTest.cs b/src/Sep.Test/SepParserTest.cs index 3feac4c1..e9ff91c8 100644 --- a/src/Sep.Test/SepParserTest.cs +++ b/src/Sep.Test/SepParserTest.cs @@ -168,9 +168,9 @@ void AssertParserOutput(ISepParser parser, int charsStart, int charsEnd, Expecte ref rowLineEndingOffset, ref lineNumber); AreEqual(expected, _colEnds, _colEndsFrom, _colEndsTo); - Assert.AreEqual(expectedNextStart, nextStart); - Assert.AreEqual(expectedRowLineEndingOffset, rowLineEndingOffset); - Assert.AreEqual(expectedLineNumber, lineNumber); + Assert.AreEqual(expectedNextStart, nextStart, nameof(nextStart)); + Assert.AreEqual(expectedRowLineEndingOffset, rowLineEndingOffset, nameof(rowLineEndingOffset)); + Assert.AreEqual(expectedLineNumber, lineNumber, nameof(lineNumber)); charsStart = nextStart; _colEndsFrom = _colEndsTo; } @@ -184,7 +184,7 @@ static void AreEqual(ReadOnlySpan expected, int[] actual, int actualFrom, i static void AreEqual(ReadOnlySpan expected, ReadOnlySpan actual) { - Assert.AreEqual(expected.Length, actual.Length); + Assert.AreEqual(expected.Length, actual.Length, nameof(actual.Length)); for (var i = 0; i < expected.Length; i++) { var e = expected[i]; From 3138f312ca4cb087599dba3bf9ea4dde14b323cc Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 11 Aug 2023 14:31:07 +0200 Subject: [PATCH 06/30] fix SepParserTest_Parse_Long_ColEndsAlmostFilled --- src/Sep.Test/SepParserTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Sep.Test/SepParserTest.cs b/src/Sep.Test/SepParserTest.cs index e9ff91c8..cb3716b2 100644 --- a/src/Sep.Test/SepParserTest.cs +++ b/src/Sep.Test/SepParserTest.cs @@ -135,12 +135,12 @@ public void SepParserTest_Parse_Long_ColEndsAlmostFilled(object parserObject) { Contract.Assume(parserObject is not null); var parser = (ISepParser)parserObject; - var charsEnd = FillChars(";ˉ;ˉ\n\rˉ" + "\"ˉ\";ˉˉ#ˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉ\rˉˉˉˉ\nˉˉ\r\nˉ;ˉ" + "ˉ\"ˉˉˉ\"ˉˉ,ˉ;ˉ.ˉ;ˉ\nˉˉˉ\r"); + var charsEnd = FillChars(";ˉ;ˉ\n\rˉ" + "\"ˉ\";ˉˉ#ˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉ;ˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉ\nˉˉ\r\nˉ;ˉ" + "ˉ\"ˉˉˉ\"ˉˉ,ˉ;ˉ.ˉ;ˉ\nˉˉˉ\r"); var paddingOffset = (parser.PaddingLength > 0 ? parser.PaddingLength : 1); _colEndsFrom = _colEnds.Length - paddingOffset; _colEndsTo = _colEndsFrom; var charsStart = 7; - var ends = new[] { 10 }.Where(i => i < (charsStart + paddingOffset)).ToArray(); + var ends = new[] { 10, 46 }.Where(i => i < (charsStart + paddingOffset)).ToArray(); var nextStart = charsStart + paddingOffset; var lineEndingOffset = 0; var expected = new Expected(ends, nextStart, lineEndingOffset, 3 + lineEndingOffset); From 82433ffde9736c21f52add7c6a4be93f93f591af Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 11 Aug 2023 14:52:28 +0200 Subject: [PATCH 07/30] fix 64 bit mask issues and casts in SepParseMask --- src/Sep/Internals/SepParseMask.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Sep/Internals/SepParseMask.cs b/src/Sep/Internals/SepParseMask.cs index 78580bf4..7d0875a9 100644 --- a/src/Sep/Internals/SepParseMask.cs +++ b/src/Sep/Internals/SepParseMask.cs @@ -26,7 +26,7 @@ internal static ref int ParseSeparatorsMask(nuint mask, int charsIndex, ref int [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static ref int ParseSeparatorsMaskLong(nuint mask, int charsIndex, ref int positionsRefCurrent) { - var count = BitOperations.PopCount((uint)mask); + var count = BitOperations.PopCount(mask); ref var positionsRefCurrentEnd = ref Add(ref positionsRefCurrent, count); var charsIndexLong = (long)((ulong)charsIndex + ((ulong)charsIndex << 32)); do @@ -138,7 +138,7 @@ internal static ref int ParseSeparatorsLineEndingsMasks(nuint separatorsMask, nu { var endingsMask = separatorsLineEndingsMask & ~separatorsMask; var lineEndingIndex = BitOperations.TrailingZeroCount(endingsMask); - if ((31 - BitOperations.LeadingZeroCount((uint)separatorsMask)) < lineEndingIndex) + if (((SizeOf() * 8 - 1) - BitOperations.LeadingZeroCount(separatorsMask)) < lineEndingIndex) { colEndsRefCurrent = ref ParseSeparatorsMask(separatorsMask, charsIndex, ref colEndsRefCurrent); From ced98780f97f0b84e1ddab130e3602070f9fd792 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 11 Aug 2023 15:34:00 +0200 Subject: [PATCH 08/30] bench on net7.0 and net8.0 only use AVX-512 on 64-bit and if hardware accelerated --- bench.ps1 | 4 +--- comparison-bench.ps1 | 2 +- src/Sep/Internals/SepParserFactory.cs | 5 +++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/bench.ps1 b/bench.ps1 index 3b033baf..8cb2bff5 100644 --- a/bench.ps1 +++ b/bench.ps1 @@ -1,3 +1 @@ -dotnet run -c Release -f net7.0 --project src\Sep.Benchmarks\Sep.Benchmarks.csproj -- ` - -m --warmupCount 5 --minIterationCount 3 --maxIterationCount 9 --runtimes net70 ` - --iterationTime 150 --filter * +dotnet run -c Release -f net8.0 --project src\Sep.Benchmarks\Sep.Benchmarks.csproj -- -m --warmupCount 5 --minIterationCount 3 --maxIterationCount 9 --runtimes net70 net80 --iterationTime 300 diff --git a/comparison-bench.ps1 b/comparison-bench.ps1 index 436241c8..f7c48356 100644 --- a/comparison-bench.ps1 +++ b/comparison-bench.ps1 @@ -1 +1 @@ -dotnet run -c Release -f net7.0 --project src/Sep.ComparisonBenchmarks/Sep.ComparisonBenchmarks.csproj -- -m --warmupCount 6 --minIterationCount 5 --runtimes net70 --iterationTime 200 --hide Type Quotes Reader RatioSD Gen0 Gen1 Gen2 Error Median StdDev +dotnet run -c Release -f net8.0 --project src/Sep.ComparisonBenchmarks/Sep.ComparisonBenchmarks.csproj -- -m --warmupCount 6 --minIterationCount 5 --runtimes net70 net80 --iterationTime 300 --hide Type Quotes Reader RatioSD Gen0 Gen1 Gen2 Error Median StdDev diff --git a/src/Sep/Internals/SepParserFactory.cs b/src/Sep/Internals/SepParserFactory.cs index ca1f0c9f..df96d941 100644 --- a/src/Sep/Internals/SepParserFactory.cs +++ b/src/Sep/Internals/SepParserFactory.cs @@ -12,7 +12,8 @@ static class SepParserFactory internal static ISepParser CreateBest(Sep sep) { #if NET8_0_OR_GREATER - if (Avx512F.IsSupported) { return new SepParserVector512NrwCmpExtMsbTzcnt(sep); } + if (Environment.Is64BitProcess && Vector512.IsHardwareAccelerated) + { return new SepParserVector512NrwCmpExtMsbTzcnt(sep); } #endif if (Avx2.IsSupported) { return new SepParserAvx2PackCmpOrMoveMaskTzcnt(sep); } if (Sse2.IsSupported) { return new SepParserSse2PackCmpOrMoveMaskTzcnt(sep); } @@ -29,7 +30,7 @@ internal static IReadOnlyDictionary> CreateFactories { var parsers = new Dictionary>(); #if NET8_0_OR_GREATER - if (Avx512F.IsSupported) //Vector512.IsHardwareAccelerated) + if (Environment.Is64BitProcess && Vector512.IsHardwareAccelerated) { Add(parsers, static sep => new SepParserVector512NrwCmpExtMsbTzcnt(sep)); } #endif if (Avx2.IsSupported) From 23397c80e1024f4f4995d4605f60f82509783839 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 11 Aug 2023 17:08:22 +0200 Subject: [PATCH 09/30] Add Avx512 specific parser --- .../SepParserAvx512PackCmpOrMoveMaskTzcnt.cs | 145 ++++++++++++++++++ src/Sep/Internals/SepParserFactory.cs | 4 + 2 files changed, 149 insertions(+) create mode 100644 src/Sep/Internals/SepParserAvx512PackCmpOrMoveMaskTzcnt.cs diff --git a/src/Sep/Internals/SepParserAvx512PackCmpOrMoveMaskTzcnt.cs b/src/Sep/Internals/SepParserAvx512PackCmpOrMoveMaskTzcnt.cs new file mode 100644 index 00000000..fd2ec6be --- /dev/null +++ b/src/Sep/Internals/SepParserAvx512PackCmpOrMoveMaskTzcnt.cs @@ -0,0 +1,145 @@ +#if NET8_0_OR_GREATER +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using static System.Runtime.CompilerServices.Unsafe; +using static nietras.SeparatedValues.SepDefaults; +using static nietras.SeparatedValues.SepParseMask; +using ISA = System.Runtime.Intrinsics.X86.Avx512BW; +using Vec = System.Runtime.Intrinsics.Vector512; +using VecI16 = System.Runtime.Intrinsics.Vector512; +using VecUI8 = System.Runtime.Intrinsics.Vector512; + +namespace nietras.SeparatedValues; + +sealed class SepParserAvx512PackCmpOrMoveMaskTzcnt : ISepParser +{ + readonly byte _separator; + readonly VecUI8 _nls = Vec.Create(LineFeedByte); + readonly VecUI8 _crs = Vec.Create(CarriageReturnByte); + readonly VecUI8 _qts = Vec.Create(QuoteByte); + readonly VecUI8 _sps; + internal nuint _quoting = 0; + + public unsafe SepParserAvx512PackCmpOrMoveMaskTzcnt(Sep sep) + { + A.Assert(Environment.Is64BitProcess); + _separator = (byte)sep.Separator; + _sps = Vec.Create(_separator); + } + + // Parses 2 x char vectors e.g. 1 byte vector + public int PaddingLength => VecUI8.Count; + + [SkipLocalsInit] + public int Parse(char[] chars, int charsIndex, int charsEnd, + int[] colEnds, ref int colEndsEnd, + scoped ref int _rowLineEndingOffset, scoped ref int _lineNumber) + { + // Method should **not** call other non-inlined methods, since this + // impacts code-generation severely. + + var separator = (char)_separator; + + var quoting = _quoting; + var rowLineEndingOffset = _rowLineEndingOffset; + var lineNumber = _lineNumber; + + chars.CheckPaddingAndIsZero(charsEnd, PaddingLength); + colEnds.CheckPadding(colEndsEnd, PaddingLength); + + A.Assert(charsIndex <= charsEnd); + A.Assert(charsEnd <= (chars.Length - PaddingLength)); + ref var charsRef = ref Add(ref MemoryMarshal.GetArrayDataReference(chars), charsIndex); + + ref var colEndsRef = ref MemoryMarshal.GetArrayDataReference(colEnds); + ref var colEndsRefCurrent = ref Add(ref colEndsRef, colEndsEnd); + ref var colEndsRefStop = ref Add(ref colEndsRef, colEnds.Length - VecUI8.Count); + + // Use instance fields to force values into registers + var nls = _nls; //Vec.Create(LineFeedByte); + var crs = _crs; //Vec.Create(CarriageReturnByte); + var qts = _qts; //Vec.Create(QuoteByte); + var sps = _sps; //Vec.Create(_separator); + + for (; charsIndex < charsEnd; charsIndex += VecUI8.Count, + charsRef = ref Add(ref charsRef, VecUI8.Count)) + { + ref var byteRef = ref As(ref charsRef); + var v0 = ReadUnaligned(ref byteRef); + var v1 = ReadUnaligned(ref Add(ref byteRef, VecUI8.Count)); + var bytes = ISA.PackUnsignedSaturate(v0, v1); + + var nlsEq = Vec.Equals(bytes, nls); + var crsEq = Vec.Equals(bytes, crs); + var qtsEq = Vec.Equals(bytes, qts); + var spsEq = Vec.Equals(bytes, sps); + + var lineEndings = nlsEq | crsEq; + var lineEndingsSeparators = spsEq | lineEndings; + var specialChars = lineEndingsSeparators | qtsEq; + + // Optimize for the case of no special character + var specialCharMask = (nuint)Vec.ExtractMostSignificantBits(specialChars); + if (specialCharMask != 0) + { + var separatorsMask = (nuint)Vec.ExtractMostSignificantBits(spsEq); + // Optimize for case of only separators i.e. no endings or quotes. + // Add quoting flags to mask as hack to skip if quoting. + var testMask = specialCharMask + quoting; + if (separatorsMask == testMask) + { + colEndsRefCurrent = ref ParseSeparatorsMask(separatorsMask, charsIndex, + ref colEndsRefCurrent); + } + else + { + var separatorLineEndingsMask = (nuint)Vec.ExtractMostSignificantBits(lineEndingsSeparators); + if (separatorLineEndingsMask == testMask) + { + colEndsRefCurrent = ref ParseSeparatorsLineEndingsMasks( + separatorsMask, separatorLineEndingsMask, + ref charsRef, ref charsIndex, separator, + ref colEndsRefCurrent, ref rowLineEndingOffset, ref lineNumber); + break; + } + else + { + colEndsRefCurrent = ref ParseAnyCharsMask(specialCharMask, + separator, ref charsRef, charsIndex, + ref rowLineEndingOffset, ref quoting, + ref colEndsRefCurrent, ref lineNumber); + // Used both to indicate row ended and if need to step +2 due to '\r\n' + if (rowLineEndingOffset != 0) + { + // Must be a col end and last is then dataIndex + charsIndex = colEndsRefCurrent + rowLineEndingOffset; + break; + } + } + } + // If current is greater than or equal than "stop", then break. + // There is no longer guaranteed space enough for next VecUI8.Count. + if (IsAddressLessThan(ref colEndsRefStop, ref colEndsRefCurrent)) + { + // Move data index so next find starts correctly + charsIndex += VecUI8.Count; + break; + } + } + } + + // ">> 2" instead of "/ sizeof(int))" // CQ: Weird with div sizeof + colEndsEnd = (int)(ByteOffset(ref colEndsRef, ref colEndsRefCurrent) >> 2); + // Step is VecUI8.Count so may go past end, ensure limited + charsIndex = Math.Min(charsEnd, charsIndex); + + _quoting = quoting; + _rowLineEndingOffset = rowLineEndingOffset; + _lineNumber = lineNumber; + + return charsIndex; + } +} +#endif diff --git a/src/Sep/Internals/SepParserFactory.cs b/src/Sep/Internals/SepParserFactory.cs index df96d941..ed1c78a2 100644 --- a/src/Sep/Internals/SepParserFactory.cs +++ b/src/Sep/Internals/SepParserFactory.cs @@ -12,6 +12,8 @@ static class SepParserFactory internal static ISepParser CreateBest(Sep sep) { #if NET8_0_OR_GREATER + if (Environment.Is64BitProcess && Avx512BW.IsSupported) + { return new SepParserAvx512PackCmpOrMoveMaskTzcnt(sep); } if (Environment.Is64BitProcess && Vector512.IsHardwareAccelerated) { return new SepParserVector512NrwCmpExtMsbTzcnt(sep); } #endif @@ -30,6 +32,8 @@ internal static IReadOnlyDictionary> CreateFactories { var parsers = new Dictionary>(); #if NET8_0_OR_GREATER + if (Environment.Is64BitProcess && Avx512BW.IsSupported) + { Add(parsers, static sep => new SepParserAvx512PackCmpOrMoveMaskTzcnt(sep)); } if (Environment.Is64BitProcess && Vector512.IsHardwareAccelerated) { Add(parsers, static sep => new SepParserVector512NrwCmpExtMsbTzcnt(sep)); } #endif From a94b4d756a343db04def6a3b778ea05a7d61fa9d Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 11 Aug 2023 17:44:09 +0200 Subject: [PATCH 10/30] Fix SepParserAvx512PackCmpOrMoveMaskTzcnt permutation --- src/Sep/Internals/SepParserAvx512PackCmpOrMoveMaskTzcnt.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Sep/Internals/SepParserAvx512PackCmpOrMoveMaskTzcnt.cs b/src/Sep/Internals/SepParserAvx512PackCmpOrMoveMaskTzcnt.cs index fd2ec6be..a445b7a7 100644 --- a/src/Sep/Internals/SepParserAvx512PackCmpOrMoveMaskTzcnt.cs +++ b/src/Sep/Internals/SepParserAvx512PackCmpOrMoveMaskTzcnt.cs @@ -69,7 +69,10 @@ public int Parse(char[] chars, int charsIndex, int charsEnd, ref var byteRef = ref As(ref charsRef); var v0 = ReadUnaligned(ref byteRef); var v1 = ReadUnaligned(ref Add(ref byteRef, VecUI8.Count)); - var bytes = ISA.PackUnsignedSaturate(v0, v1); + var packed = ISA.PackUnsignedSaturate(v0, v1); + // Pack interleaves the two vectors need to permute them back + var permuteIndices = Vec.Create(0L, 2L, 4L, 6L, 1L, 3L, 5L, 7L); + var bytes = ISA.PermuteVar8x64(packed.AsInt64(), permuteIndices).AsByte(); var nlsEq = Vec.Equals(bytes, nls); var crsEq = Vec.Equals(bytes, crs); From 9edafd2d738a3454f66aa66192f3b45192be8047 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 11 Aug 2023 17:46:20 +0200 Subject: [PATCH 11/30] add Sequence test --- src/Sep.Test/SepParserTest.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Sep.Test/SepParserTest.cs b/src/Sep.Test/SepParserTest.cs index cb3716b2..82dfc865 100644 --- a/src/Sep.Test/SepParserTest.cs +++ b/src/Sep.Test/SepParserTest.cs @@ -53,6 +53,22 @@ public void SepParserTest_Properties(object parserObject) Assert.IsTrue(parser.PaddingLength >= 0); } + [TestMethod] + [DynamicData(nameof(Parsers))] + public void SepParserTest_Parse_Sequence(object parserObject) + { + Contract.Assume(parserObject is not null); + var parser = (ISepParser)parserObject; + + var charsEnd = FillChars(new(Enumerable.Range(0, 256).Select(i => (char)i).ToArray())); + var rowLineEndingOffset = 0; + var lineNumber = 3; + + var nextStart = parser.Parse(_chars, charsIndex: 0, charsEnd: charsEnd, + colEnds: _colEnds, colEndsEnd: ref _colEndsTo, + ref rowLineEndingOffset, lineNumber: ref lineNumber); + } + [TestMethod] [DynamicData(nameof(Parsers))] public void SepParserTest_Parse_Short(object parserObject) From e045b73daaa45ffb1dbe162f2054256f5ca2ed35 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 11 Aug 2023 18:17:42 +0200 Subject: [PATCH 12/30] 0.2.3 --- src/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index ea1c71da..51576d60 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -2,7 +2,7 @@ 0.2.0 - 0.2.2 + 0.2.3 $(FileVersion) $(InformationalVersion) From 28cccde1ff954ad698614b744cd43641d88ab032 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 11 Aug 2023 18:22:11 +0200 Subject: [PATCH 13/30] add Vector512 parser to factories on 64-bit no matter what --- src/Sep/Internals/SepParserFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Sep/Internals/SepParserFactory.cs b/src/Sep/Internals/SepParserFactory.cs index ed1c78a2..4259c40c 100644 --- a/src/Sep/Internals/SepParserFactory.cs +++ b/src/Sep/Internals/SepParserFactory.cs @@ -34,7 +34,7 @@ internal static IReadOnlyDictionary> CreateFactories #if NET8_0_OR_GREATER if (Environment.Is64BitProcess && Avx512BW.IsSupported) { Add(parsers, static sep => new SepParserAvx512PackCmpOrMoveMaskTzcnt(sep)); } - if (Environment.Is64BitProcess && Vector512.IsHardwareAccelerated) + if (Environment.Is64BitProcess) { Add(parsers, static sep => new SepParserVector512NrwCmpExtMsbTzcnt(sep)); } #endif if (Avx2.IsSupported) From 2c12ee75309b03187e4036a7c9edfa9d9cdd85a9 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 11 Aug 2023 18:31:27 +0200 Subject: [PATCH 14/30] update bench yml to net8.0 --- .github/workflows/bench.yml | 2 +- .github/workflows/comparison-bench.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 4f535806..a85879f8 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -24,4 +24,4 @@ jobs: - name: Build run: dotnet build -c ${{ matrix.configuration }} --no-restore - name: Bench - run: dotnet run -c ${{ matrix.configuration }} -f net7.0 --no-restore --project src/Sep.Benchmarks/Sep.Benchmarks.csproj -- -m -d --iterationTime 150 + run: dotnet run -c ${{ matrix.configuration }} -f net8.0 --no-restore --project src/Sep.Benchmarks/Sep.Benchmarks.csproj -- -m -d --iterationTime 300 diff --git a/.github/workflows/comparison-bench.yml b/.github/workflows/comparison-bench.yml index 489b4664..1aed00bb 100644 --- a/.github/workflows/comparison-bench.yml +++ b/.github/workflows/comparison-bench.yml @@ -24,4 +24,4 @@ jobs: - name: Build run: dotnet build -c ${{ matrix.configuration }} --no-restore - name: Bench - run: dotnet run -c ${{ matrix.configuration }} -f net7.0 --no-restore --project src/Sep.ComparisonBenchmarks/Sep.ComparisonBenchmarks.csproj -- -m --warmupCount 3 --iterationTime 150 + run: dotnet run -c ${{ matrix.configuration }} -f net8.0 --no-restore --project src/Sep.ComparisonBenchmarks/Sep.ComparisonBenchmarks.csproj -- -m --iterationTime 300 From 19cae6873e2e743aa103590d27350c4a9f281c4d Mon Sep 17 00:00:00 2001 From: ntr Date: Sat, 12 Aug 2023 12:44:41 +0200 Subject: [PATCH 15/30] Change SepParseMaskTest to use nuint to ensure 64-bit masks covered --- src/Sep.Test/SepParseMaskTest.cs | 13 ++++++---- .../SepParseMaskTest_ParseAnyCharsMask.cs | 10 ++++---- ...askTest_ParseSeparatorsLineEndingsMasks.cs | 24 +++++++++---------- .../SepParseMaskTest_ParseSeparatorsMask.cs | 8 +++---- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/src/Sep.Test/SepParseMaskTest.cs b/src/Sep.Test/SepParseMaskTest.cs index 2509c853..29df4195 100644 --- a/src/Sep.Test/SepParseMaskTest.cs +++ b/src/Sep.Test/SepParseMaskTest.cs @@ -10,20 +10,23 @@ public partial class SepParseMaskTest { const char Separator = ';'; const int CharsIndexOffset = 17; + static readonly int s_nativeBitSize = Unsafe.SizeOf() * 8; - static uint MaskFor(ReadOnlySpan chars) + static nuint MaskFor(ReadOnlySpan chars) { - var mask = 0; - for (var i = 0; i < Math.Min(chars.Length, 32); i++) + nuint mask = 0; + for (var i = 0; i < LengthForMask(chars.Length); i++) { if (IsSpecialChar(chars[i])) { - mask |= 1 << i; + mask |= (nuint)1 << i; } } - return (uint)mask; + return mask; } + static int LengthForMask(int length) => Math.Min(length, s_nativeBitSize); + static bool IsSpecialChar(char c) => c switch { Separator => true, diff --git a/src/Sep.Test/SepParseMaskTest_ParseAnyCharsMask.cs b/src/Sep.Test/SepParseMaskTest_ParseAnyCharsMask.cs index 67146ca3..32eab710 100644 --- a/src/Sep.Test/SepParseMaskTest_ParseAnyCharsMask.cs +++ b/src/Sep.Test/SepParseMaskTest_ParseAnyCharsMask.cs @@ -26,7 +26,7 @@ public void SepParseMaskTest_ParseAnyCharsMask_Ordinary() rowLineEndingOffset: 0, expectedRowLineEndingOffset: 0, lineNumber: 2, expectedLineNumber: 2); - AssertParseAnyCharsMask(new string('a', 31) + "\r\n", new[] { 31 }, + AssertParseAnyCharsMask(new string('a', s_nativeBitSize - 1) + "\r\n", new[] { s_nativeBitSize - 1 }, rowLineEndingOffset: 0, expectedRowLineEndingOffset: 2, lineNumber: 2, expectedLineNumber: 3); } @@ -46,13 +46,13 @@ public void SepParseMaskTest_ParseAnyCharsMask_Quotes() rowLineEndingOffset: 0, expectedRowLineEndingOffset: 1, lineNumber: 2, expectedLineNumber: 4); - AssertParseAnyCharsMask("\"" + new string('a', 30) + "\r\n", Array.Empty(), + AssertParseAnyCharsMask("\"" + new string('a', s_nativeBitSize - 2) + "\r\n", Array.Empty(), rowLineEndingOffset: 0, expectedRowLineEndingOffset: 0, expectedQuoting: 1, lineNumber: 2, expectedLineNumber: 2); // Line number first increment when \n handled - AssertParseAnyCharsMask("\"" + new string('\r', 29) + "\"\r\n", new[] { 31 }, + AssertParseAnyCharsMask("\"" + new string('\r', s_nativeBitSize - 3) + "\"\r\n", new[] { s_nativeBitSize - 1 }, rowLineEndingOffset: 0, expectedRowLineEndingOffset: 2, - lineNumber: 2, expectedLineNumber: 3 + 29); + lineNumber: 2, expectedLineNumber: 3 + s_nativeBitSize - 3); } static void AssertParseAnyCharsMask(string chars, int[] expected, @@ -62,7 +62,7 @@ static void AssertParseAnyCharsMask(string chars, int[] expected, { for (var i = 0; i < expected.Length; ++i) { expected[i] += CharsIndexOffset; } var mask = MaskFor(chars); - Span colEnds = stackalloc int[32 + 1]; + Span colEnds = stackalloc int[s_nativeBitSize + 1]; ref var start = ref colEnds[0]; ref var end = ref ParseAnyCharsMask(mask, Separator, diff --git a/src/Sep.Test/SepParseMaskTest_ParseSeparatorsLineEndingsMasks.cs b/src/Sep.Test/SepParseMaskTest_ParseSeparatorsLineEndingsMasks.cs index aa7c6399..d2ea7d62 100644 --- a/src/Sep.Test/SepParseMaskTest_ParseSeparatorsLineEndingsMasks.cs +++ b/src/Sep.Test/SepParseMaskTest_ParseSeparatorsLineEndingsMasks.cs @@ -26,7 +26,7 @@ public void SepParseMaskTest_ParseSeparatorsLineEndingsMasks_Ordinary() rowLineEndingOffset: 0, expectedRowLineEndingOffset: 1, lineNumber: 2, expectedLineNumber: 3); - AssertParseSeparatorsLineEndingsMasks(new string('a', 31) + "\r\n", new[] { 31 }, + AssertParseSeparatorsLineEndingsMasks(new string('a', s_nativeBitSize - 1) + "\r\n", new[] { s_nativeBitSize - 1 }, rowLineEndingOffset: 0, expectedRowLineEndingOffset: 2, lineNumber: 2, expectedLineNumber: 3); } @@ -39,7 +39,7 @@ static void AssertParseSeparatorsLineEndingsMasks(string chars, int[] expected, for (var i = 0; i < expected.Length; ++i) { expected[i] += CharsIndexOffset; } var separatorsMask = SeparatorsMaskFor(chars); var lineEndingsMask = LineEndingsMaskFor(chars); - Span colEnds = stackalloc int[32 + 1]; + Span colEnds = stackalloc int[s_nativeBitSize + 1]; ref var start = ref colEnds[0]; var charsIndex = CharsIndexOffset; @@ -55,30 +55,30 @@ ref MemoryMarshal.GetReference(chars), ref charsIndex, Separator, expectedLineNumber, lineNumber); } - static uint SeparatorsMaskFor(ReadOnlySpan chars) + static nuint SeparatorsMaskFor(ReadOnlySpan chars) { - var mask = 0; - for (var i = 0; i < Math.Min(chars.Length, 32); i++) + nuint mask = 0; + for (var i = 0; i < LengthForMask(chars.Length); i++) { if (chars[i] == Separator) { - mask |= 1 << i; + mask |= (nuint)1 << i; } } - return (uint)mask; + return mask; } - static uint LineEndingsMaskFor(ReadOnlySpan chars) + static nuint LineEndingsMaskFor(ReadOnlySpan chars) { - var mask = 0; - for (var i = 0; i < Math.Min(chars.Length, 32); i++) + nuint mask = 0; + for (var i = 0; i < LengthForMask(chars.Length); i++) { var c = chars[i]; if (c == SepDefaults.LineFeed || c == SepDefaults.CarriageReturn) { - mask |= 1 << i; + mask |= (nuint)1 << i; } } - return (uint)mask; + return mask; } } diff --git a/src/Sep.Test/SepParseMaskTest_ParseSeparatorsMask.cs b/src/Sep.Test/SepParseMaskTest_ParseSeparatorsMask.cs index 605a8e0b..da50d815 100644 --- a/src/Sep.Test/SepParseMaskTest_ParseSeparatorsMask.cs +++ b/src/Sep.Test/SepParseMaskTest_ParseSeparatorsMask.cs @@ -10,7 +10,7 @@ namespace nietras.SeparatedValues.Test; public partial class SepParseMaskTest { - sealed record Data(uint Mask, int[] Expected); + sealed record Data(nuint Mask, int[] Expected); public delegate ref int ParseSeparatorsMaskMethod( nuint mask, int charsIndex, ref int colEndsRef); @@ -19,11 +19,11 @@ public delegate ref int ParseSeparatorsMaskMethod( { new(0b0000_0000_0100_0001, new[] { 0, 6, }), new(0b1000_1001_0100_0001, new[] { 0, 6, 8, 11, 15 }), - new(uint.MaxValue, Enumerable.Range(0, 32).ToArray()), + new(nuint.MaxValue, Enumerable.Range(0, s_nativeBitSize).ToArray()), // Empty mask will output index after mask, that is expected, check mask // before calling parse mask. Some methods will not do the same since // using PopCount. - // new(0, new[] { 32 }), + // new(0, new[] { s_nativeBitSize }), }; static IEnumerable Methods => new object[][] @@ -46,7 +46,7 @@ public void SepParseMaskTest_ParseSeparatorsMask_Test_(ParseSeparatorsMaskMethod static void AssertParseSeparatorsMask( nuint mask, ParseSeparatorsMaskMethod parse, int[] expected) { - Span colEnds = stackalloc int[32 + 1]; + Span colEnds = stackalloc int[s_nativeBitSize + 1]; ref var start = ref MemoryMarshal.GetReference(colEnds); ref var end = ref parse(mask, CharsIndexOffset, ref start); From 7527907150c8446c13b04bb3a25864d3f77e8ded Mon Sep 17 00:00:00 2001 From: ntr Date: Sat, 12 Aug 2023 12:55:28 +0200 Subject: [PATCH 16/30] nits --- src/Sep.Test/SepParserTest.cs | 2 ++ src/Sep/Internals/SepAssert.cs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Sep.Test/SepParserTest.cs b/src/Sep.Test/SepParserTest.cs index 82dfc865..663cb349 100644 --- a/src/Sep.Test/SepParserTest.cs +++ b/src/Sep.Test/SepParserTest.cs @@ -67,6 +67,8 @@ public void SepParserTest_Parse_Sequence(object parserObject) var nextStart = parser.Parse(_chars, charsIndex: 0, charsEnd: charsEnd, colEnds: _colEnds, colEndsEnd: ref _colEndsTo, ref rowLineEndingOffset, lineNumber: ref lineNumber); + + // No assert, test is mainly for debugging SIMD code easily } [TestMethod] diff --git a/src/Sep/Internals/SepAssert.cs b/src/Sep/Internals/SepAssert.cs index 5482e792..881bcd72 100644 --- a/src/Sep/Internals/SepAssert.cs +++ b/src/Sep/Internals/SepAssert.cs @@ -12,7 +12,7 @@ namespace nietras.SeparatedValues; /// Many unit test frameworks do not handle very well including MSTest, /// so instead defining some custom assert code that throws an ordinary -/// exception instead and provides some more details. +/// exception and provides some more details. /// [ExcludeFromCodeCoverage] static class SepAssert From 39b2f0d77275747da09e6c1d76170c60b315890e Mon Sep 17 00:00:00 2001 From: ntr Date: Sat, 12 Aug 2023 13:03:35 +0200 Subject: [PATCH 17/30] nits in SepParseSeparatorsMaskBench --- src/Sep.Benchmarks/SepParseSeparatorsMaskBench.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Sep.Benchmarks/SepParseSeparatorsMaskBench.cs b/src/Sep.Benchmarks/SepParseSeparatorsMaskBench.cs index b6649dbf..790278c5 100644 --- a/src/Sep.Benchmarks/SepParseSeparatorsMaskBench.cs +++ b/src/Sep.Benchmarks/SepParseSeparatorsMaskBench.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; @@ -15,9 +16,9 @@ public readonly record struct MaskSpec(uint Mask) readonly MaskSpec[] _masks; MaskSpec _mask; - uint _maskValue; + nuint _maskValue; readonly int _dataIndex = 17; - readonly int* _colEnds = (int*)NativeMemory.Alloc(32, sizeof(int)); + readonly int* _colEnds = (int*)NativeMemory.Alloc((nuint)Unsafe.SizeOf() * 8, sizeof(int)); public SepParseSeparatorsMaskBench() { From bcf9e651a5dc162c99a5ab9d9af75a38f7143618 Mon Sep 17 00:00:00 2001 From: ntr Date: Sat, 12 Aug 2023 13:03:51 +0200 Subject: [PATCH 18/30] update README with vectorization paths --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1a528a73..6a9f3978 100644 --- a/README.md +++ b/README.md @@ -22,10 +22,10 @@ and highly efficient implementation. changes to input or output. What you read/write is what you get. This means there is no "automatic" escaping/unescaping of quotes, for example. * **🚀 Fast** - blazing fast with both architecture specific and cross-platform -SIMD vectorized parsing. Uses -[csFastFloat](https://github.com/CarlVerret/csFastFloat) for fast parsing of -floating points. Reads or writes one row at a time efficiently with [detailed -benchmarks](#comparison-benchmarks) to prove it. +SIMD vectorized parsing incl. 64/128/256/512-bit paths e.g. AVX2, AVX-512 (.NET +8.0+), NEON. Uses [csFastFloat](https://github.com/CarlVerret/csFastFloat) for +fast parsing of floating points. Reads or writes one row at a time efficiently +with [detailed benchmarks](#comparison-benchmarks) to prove it. * **🗑️ Zero allocation** - intelligent and efficient memory management allowing for zero allocations after warmup incl. supporting use cases of reading or writing arrays of values (e.g. features) easily without repeated allocations. From 81c70ddfcd6a275d02aa9dd25de89dfc758430e0 Mon Sep 17 00:00:00 2001 From: ntr Date: Sun, 20 Aug 2023 11:48:55 +0200 Subject: [PATCH 19/30] save bench to custom folder with name --- .../PackageAssetsBench.cs | 3 +- src/Sep.ComparisonBenchmarks/Program.cs | 73 +++++++++++++------ 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/src/Sep.ComparisonBenchmarks/PackageAssetsBench.cs b/src/Sep.ComparisonBenchmarks/PackageAssetsBench.cs index f16c8414..7ce6a977 100644 --- a/src/Sep.ComparisonBenchmarks/PackageAssetsBench.cs +++ b/src/Sep.ComparisonBenchmarks/PackageAssetsBench.cs @@ -17,7 +17,8 @@ namespace nietras.SeparatedValues.ComparisonBenchmarks; // particular interesting benchmark of CSV parsers since all it tests is // splitting lines to strings basically, nothing else. This can be seen in: // https://github.com/nietras/NCsvPerf/blob/3e07bbbef6ccbbce61f66cea098d4ed10947a494/NCsvPerf/CsvReadable/Benchmarks/PackageAsset.cs#L52 -[HideColumns("InvocationCount")] +[MemoryDiagnoser] +[HideColumns("InvocationCount", "Job", "IterationTime", "MinIterationCount", "MaxIterationCount", "Type", "Quotes", "Reader", "RatioSD", "Gen0", "Gen1", "Gen2", "Error", "Median", "StdDev")] [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory, BenchmarkLogicalGroupRule.ByParams)] public abstract class PackageAssetsBench { diff --git a/src/Sep.ComparisonBenchmarks/Program.cs b/src/Sep.ComparisonBenchmarks/Program.cs index 0f8503fc..df4b430e 100644 --- a/src/Sep.ComparisonBenchmarks/Program.cs +++ b/src/Sep.ComparisonBenchmarks/Program.cs @@ -3,14 +3,21 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading; using BenchmarkDotNet.Columns; using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Exporters; +using BenchmarkDotNet.Jobs; +using BenchmarkDotNet.Loggers; using BenchmarkDotNet.Parameters; using BenchmarkDotNet.Reports; using BenchmarkDotNet.Running; using nietras.SeparatedValues.ComparisonBenchmarks; +using Perfolizer.Horology; + [assembly: System.Runtime.InteropServices.ComVisible(false)] Action log = t => { Console.WriteLine(t); Trace.WriteLine(t); }; @@ -20,37 +27,63 @@ await PackageAssetsTestData.EnsurePackageAssets().ConfigureAwait(true); // Use args as switch to run BDN or not e.g. BDN only run when using script -if (args.Length > 0) +if (true || args.Length > 0) { - var config = (Debugger.IsAttached ? new DebugInProcessConfig() : DefaultConfig.Instance) + var baseConfig = ManualConfig.CreateEmpty() + .AddColumnProvider(DefaultColumnProviders.Instance) + .AddExporter(MarkdownExporter.GitHub) + .AddLogger(ConsoleLogger.Default); + + var config = +#if DEBUG + baseConfig +#else + (Debugger.IsAttached ? new DebugInProcessConfig() : DefaultConfig.Instance) +#endif .WithSummaryStyle(SummaryStyle.Default.WithMaxParameterColumnWidth(120)) .AddColumn(MB()) .AddColumn(MBPerSec()) .AddColumn(RowsStatisticColumn.NSPerRow()) - .WithOption(ConfigOptions.JoinSummary, true); + .WithOption(ConfigOptions.JoinSummary, true) +#if DEBUG + .AddJob(Job.InProcess.WithIterationTime(TimeInterval.FromMilliseconds(100)).WithMinIterationCount(2).WithMaxIterationCount(5)) +#endif + ; //BenchmarkSwitcher.FromAssembly(Assembly.GetExecutingAssembly()).Run(args, config); - var benchTypesSet = new Type[][] + var nameToBenchTypesSet = new Dictionary() { - new[] { typeof(RowPackageAssetsBench), typeof(ColsPackageAssetsBench), typeof(AssetPackageAssetsBench), }, - new[] { typeof(QuotesRowPackageAssetsBench), typeof(QuotesColsPackageAssetsBench), typeof(QuotesAssetPackageAssetsBench), }, - new[] { typeof(RowFloatsReaderBench), typeof(ColsFloatsReaderBench), typeof(FloatsFloatsReaderBench), }, + { nameof(PackageAssetsBench), new[] { typeof(RowPackageAssetsBench), typeof(ColsPackageAssetsBench), typeof(AssetPackageAssetsBench), } }, + { nameof(PackageAssetsBench) + "Quotes", new[] { typeof(QuotesRowPackageAssetsBench), typeof(QuotesColsPackageAssetsBench), typeof(QuotesAssetPackageAssetsBench), } }, + { nameof(FloatsReaderBench), new[] { typeof(RowFloatsReaderBench), typeof(ColsFloatsReaderBench), typeof(FloatsFloatsReaderBench), } }, }; - foreach (var benchTypes in benchTypesSet) + foreach (var (name, benchTypes) in nameToBenchTypesSet) { var summaries = BenchmarkRunner.Run(benchTypes, config, args); foreach (var s in summaries) { - log(s.ResultsDirectoryPath); - log(s.LogFilePath); - foreach (var r in s.Reports) - { - log(r.GetHardwareIntrinsicsInfo()!); - var metrics = r.Metrics; - var stats = r.ResultStatistics; + var cpuInfo = s.HostEnvironmentInfo.CpuInfo.Value; + var processorName = cpuInfo.ProcessorName; + var processorNameInDirectory = processorName.Replace(" Processor", "").Replace(" ", "."); + + var sourceDirectory = GetSourceDirectory(); + var directory = $"{sourceDirectory}/../../benchmarks/{processorNameInDirectory}"; + if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } + var filePath = Path.Combine(directory, $"{name}.md"); + + var exporter = MarkdownExporter.GitHub; - } + using var stream = new MemoryStream(); + using var writer = new StreamWriter(stream); + using var logger = new StreamLogger(writer); + exporter.ExportToLog(s, logger); + logger.Flush(); + stream.Position = 0; + using var reader = new StreamReader(stream); + var text = reader.ReadToEnd(); + text = text.Replace("**", ""); + File.WriteAllText(filePath, text); } } } @@ -99,10 +132,4 @@ static long BytesFromReaderSpec(IReadOnlyList parameters) return parameters.Select(p => p.Value as ReaderSpec).Where(r => r is not null).Single()!.Bytes; } -//class Config : ManualConfig -//{ -// public Config() -// { -// AddJob(Job.MediumRun.WithToolchain(BenchmarkDotNet.Toolchains.InProcess.Emit.InProcessEmitToolchain.Instance).WithId("InProcess")); -// } -//} +static string GetSourceDirectory([CallerFilePath] string filePath = "") => Path.GetDirectoryName(filePath)!; From c6860d356c720415d546ab4c304bb142e1da047b Mon Sep 17 00:00:00 2001 From: ntr Date: Sun, 20 Aug 2023 12:01:05 +0200 Subject: [PATCH 20/30] add benchmarks to git --- .../FloatsReaderBench.md | 41 ++++++++++++++++++ .../PackageAssetsBench.md | 42 +++++++++++++++++++ .../PackageAssetsBenchQuotes.md | 42 +++++++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 benchmarks/AMD.Ryzen.9.5950X.16-Core/FloatsReaderBench.md create mode 100644 benchmarks/AMD.Ryzen.9.5950X.16-Core/PackageAssetsBench.md create mode 100644 benchmarks/AMD.Ryzen.9.5950X.16-Core/PackageAssetsBenchQuotes.md diff --git a/benchmarks/AMD.Ryzen.9.5950X.16-Core/FloatsReaderBench.md b/benchmarks/AMD.Ryzen.9.5950X.16-Core/FloatsReaderBench.md new file mode 100644 index 00000000..4b8580d9 --- /dev/null +++ b/benchmarks/AMD.Ryzen.9.5950X.16-Core/FloatsReaderBench.md @@ -0,0 +1,41 @@ +``` ini + +BenchmarkDotNet=v0.13.5, OS=Windows 10 (10.0.19044.3086/21H2/November2021Update) +AMD Ryzen 9 5950X, 1 CPU, 32 logical and 16 physical cores +.NET SDK=8.0.100-preview.7.23376.3 + [Host] : .NET 8.0.0 (8.0.23.37506), X64 RyuJIT AVX2 + Job-ZCBCZS : .NET 7.0.10 (7.0.1023.36312), X64 RyuJIT AVX2 + Job-KHRFRP : .NET 8.0.0 (8.0.23.37506), X64 RyuJIT AVX2 + +InvocationCount=Default IterationTime=300.0000 ms MinIterationCount=5 +WarmupCount=6 Reader=String + +``` +| Method | Runtime | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | +|---------- |--------- |------- |------ |-----------:|------:|---:|--------:|-------:|------------:|------------:| +| Sep______ | .NET 7.0 | Row | 25000 | 2.689 ms | 1.00 | 27 | 10137.6 | 107.6 | 1.56 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Row | 25000 | 3.017 ms | 1.12 | 27 | 9036.1 | 120.7 | 10.55 KB | 6.78 | +| ReadLine_ | .NET 7.0 | Row | 25000 | 13.916 ms | 5.14 | 27 | 1959.1 | 556.6 | 89986.83 KB | 57,808.36 | +| CsvHelper | .NET 7.0 | Row | 25000 | 49.716 ms | 18.60 | 27 | 548.4 | 1988.7 | 20.74 KB | 13.32 | +| Sep______ | .NET 8.0 | Row | 25000 | 2.610 ms | 0.97 | 27 | 10445.9 | 104.4 | 1.56 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Row | 25000 | 2.968 ms | 1.10 | 27 | 9185.7 | 118.7 | 10.55 KB | 6.78 | +| ReadLine_ | .NET 8.0 | Row | 25000 | 13.343 ms | 4.98 | 27 | 2043.3 | 533.7 | 89986.83 KB | 57,808.35 | +| CsvHelper | .NET 8.0 | Row | 25000 | 34.199 ms | 12.72 | 27 | 797.2 | 1368.0 | 20.61 KB | 13.24 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Cols | 25000 | 3.097 ms | 1.00 | 27 | 8804.5 | 123.9 | 1.56 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Cols | 25000 | 4.980 ms | 1.61 | 27 | 5474.5 | 199.2 | 10.56 KB | 6.77 | +| ReadLine_ | .NET 7.0 | Cols | 25000 | 13.959 ms | 4.51 | 27 | 1953.2 | 558.3 | 89986.84 KB | 57,735.92 | +| CsvHelper | .NET 7.0 | Cols | 25000 | 53.680 ms | 17.10 | 27 | 507.9 | 2147.2 | 28451.27 KB | 18,254.45 | +| Sep______ | .NET 8.0 | Cols | 25000 | 3.059 ms | 0.99 | 27 | 8912.6 | 122.4 | 1.56 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Cols | 25000 | 4.840 ms | 1.56 | 27 | 5632.9 | 193.6 | 10.55 KB | 6.77 | +| ReadLine_ | .NET 8.0 | Cols | 25000 | 13.615 ms | 4.40 | 27 | 2002.4 | 544.6 | 89986.83 KB | 57,735.91 | +| CsvHelper | .NET 8.0 | Cols | 25000 | 37.445 ms | 12.09 | 27 | 728.1 | 1497.8 | 28451.15 KB | 18,254.37 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Floats | 25000 | 33.069 ms | 1.00 | 27 | 824.4 | 1322.8 | 8.89 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Floats | 25000 | 71.582 ms | 2.16 | 27 | 380.9 | 2863.3 | 18.86 KB | 2.12 | +| ReadLine_ | .NET 7.0 | Floats | 25000 | 82.038 ms | 2.48 | 27 | 332.3 | 3281.5 | 89993.42 KB | 10,122.28 | +| CsvHelper | .NET 7.0 | Floats | 25000 | 127.852 ms | 3.86 | 27 | 213.2 | 5114.1 | 22039.48 KB | 2,478.96 | +| Sep______ | .NET 8.0 | Floats | 25000 | 22.521 ms | 0.68 | 27 | 1210.6 | 900.8 | 9.11 KB | 1.02 | +| Sylvan___ | .NET 8.0 | Floats | 25000 | 65.072 ms | 1.97 | 27 | 419.0 | 2602.9 | 18.84 KB | 2.12 | +| ReadLine_ | .NET 8.0 | Floats | 25000 | 72.803 ms | 2.20 | 27 | 374.5 | 2912.1 | 89990.3 KB | 10,121.93 | +| CsvHelper | .NET 8.0 | Floats | 25000 | 112.180 ms | 3.39 | 27 | 243.0 | 4487.2 | 22035.55 KB | 2,478.51 | diff --git a/benchmarks/AMD.Ryzen.9.5950X.16-Core/PackageAssetsBench.md b/benchmarks/AMD.Ryzen.9.5950X.16-Core/PackageAssetsBench.md new file mode 100644 index 00000000..e11b7bd7 --- /dev/null +++ b/benchmarks/AMD.Ryzen.9.5950X.16-Core/PackageAssetsBench.md @@ -0,0 +1,42 @@ +``` ini + +BenchmarkDotNet=v0.13.5, OS=Windows 10 (10.0.19044.3086/21H2/November2021Update) +AMD Ryzen 9 5950X, 1 CPU, 32 logical and 16 physical cores +.NET SDK=8.0.100-preview.7.23376.3 + [Host] : .NET 8.0.0 (8.0.23.37506), X64 RyuJIT AVX2 + Job-ZCBCZS : .NET 7.0.10 (7.0.1023.36312), X64 RyuJIT AVX2 + Job-KHRFRP : .NET 8.0.0 (8.0.23.37506), X64 RyuJIT AVX2 + +InvocationCount=Default IterationTime=300.0000 ms MaxIterationCount=Default +MinIterationCount=5 WarmupCount=6 Quotes=False +Reader=String + +``` +| Method | Runtime | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | +|---------- |--------- |------ |------ |-----------:|------:|---:|--------:|-------:|-------------:|------------:| +| Sep______ | .NET 7.0 | Row | 50000 | 2.565 ms | 1.00 | 29 | 11375.3 | 51.3 | 1.13 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Row | 50000 | 3.301 ms | 1.29 | 29 | 8840.1 | 66.0 | 7.17 KB | 6.34 | +| ReadLine_ | .NET 7.0 | Row | 50000 | 13.676 ms | 5.26 | 29 | 2133.7 | 273.5 | 88608.25 KB | 78,287.18 | +| CsvHelper | .NET 7.0 | Row | 50000 | 63.120 ms | 24.57 | 29 | 462.3 | 1262.4 | 20.65 KB | 18.25 | +| Sep______ | .NET 8.0 | Row | 50000 | 2.458 ms | 0.96 | 29 | 11872.7 | 49.2 | 1.13 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Row | 50000 | 3.053 ms | 1.19 | 29 | 9558.2 | 61.1 | 7.17 KB | 6.33 | +| ReadLine_ | .NET 8.0 | Row | 50000 | 12.642 ms | 4.96 | 29 | 2308.3 | 252.8 | 88608.24 KB | 78,287.18 | +| CsvHelper | .NET 8.0 | Row | 50000 | 44.515 ms | 17.37 | 29 | 655.5 | 890.3 | 20.59 KB | 18.19 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Cols | 50000 | 3.328 ms | 1.00 | 29 | 8769.4 | 66.6 | 1.13 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Cols | 50000 | 5.773 ms | 1.74 | 29 | 5054.4 | 115.5 | 7.18 KB | 6.33 | +| ReadLine_ | .NET 7.0 | Cols | 50000 | 13.962 ms | 4.11 | 29 | 2090.0 | 279.2 | 88608.25 KB | 78,152.32 | +| CsvHelper | .NET 7.0 | Cols | 50000 | 79.138 ms | 23.81 | 29 | 368.7 | 1582.8 | 446.31 KB | 393.65 | +| Sep______ | .NET 8.0 | Cols | 50000 | 3.188 ms | 0.96 | 29 | 9153.5 | 63.8 | 1.13 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Cols | 50000 | 5.598 ms | 1.68 | 29 | 5213.0 | 112.0 | 7.17 KB | 6.33 | +| ReadLine_ | .NET 8.0 | Cols | 50000 | 12.944 ms | 3.86 | 29 | 2254.4 | 258.9 | 88608.24 KB | 78,152.32 | +| CsvHelper | .NET 8.0 | Cols | 50000 | 71.520 ms | 21.27 | 29 | 408.0 | 1430.4 | 446.29 KB | 393.62 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Asset | 50000 | 30.729 ms | 1.00 | 29 | 949.6 | 614.6 | 13799.67 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Asset | 50000 | 42.129 ms | 1.37 | 29 | 692.7 | 842.6 | 14025.03 KB | 1.02 | +| ReadLine_ | .NET 7.0 | Asset | 50000 | 115.299 ms | 3.75 | 29 | 253.1 | 2306.0 | 102133.39 KB | 7.40 | +| CsvHelper | .NET 7.0 | Asset | 50000 | 104.802 ms | 3.41 | 29 | 278.4 | 2096.0 | 13972.08 KB | 1.01 | +| Sep______ | .NET 8.0 | Asset | 50000 | 30.395 ms | 0.99 | 29 | 960.1 | 607.9 | 13799.62 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Asset | 50000 | 38.198 ms | 1.24 | 29 | 764.0 | 764.0 | 14026.64 KB | 1.02 | +| ReadLine_ | .NET 8.0 | Asset | 50000 | 109.821 ms | 3.53 | 29 | 265.7 | 2196.4 | 102133.38 KB | 7.40 | +| CsvHelper | .NET 8.0 | Asset | 50000 | 85.305 ms | 2.78 | 29 | 342.1 | 1706.1 | 13972.36 KB | 1.01 | diff --git a/benchmarks/AMD.Ryzen.9.5950X.16-Core/PackageAssetsBenchQuotes.md b/benchmarks/AMD.Ryzen.9.5950X.16-Core/PackageAssetsBenchQuotes.md new file mode 100644 index 00000000..ef9322ea --- /dev/null +++ b/benchmarks/AMD.Ryzen.9.5950X.16-Core/PackageAssetsBenchQuotes.md @@ -0,0 +1,42 @@ +``` ini + +BenchmarkDotNet=v0.13.5, OS=Windows 10 (10.0.19044.3086/21H2/November2021Update) +AMD Ryzen 9 5950X, 1 CPU, 32 logical and 16 physical cores +.NET SDK=8.0.100-preview.7.23376.3 + [Host] : .NET 8.0.0 (8.0.23.37506), X64 RyuJIT AVX2 + Job-ZCBCZS : .NET 7.0.10 (7.0.1023.36312), X64 RyuJIT AVX2 + Job-KHRFRP : .NET 8.0.0 (8.0.23.37506), X64 RyuJIT AVX2 + +InvocationCount=Default IterationTime=300.0000 ms MaxIterationCount=Default +MinIterationCount=5 WarmupCount=6 Quotes=True +Reader=String + +``` +| Method | Runtime | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | +|---------- |--------- |------ |------ |-----------:|------:|---:|-------:|-------:|-------------:|------------:| +| Sep______ | .NET 7.0 | Row | 50000 | 7.414 ms | 1.00 | 33 | 4501.8 | 148.3 | 1.15 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Row | 50000 | 21.528 ms | 2.91 | 33 | 1550.4 | 430.6 | 7.33 KB | 6.40 | +| ReadLine_ | .NET 7.0 | Row | 50000 | 15.944 ms | 2.13 | 33 | 2093.4 | 318.9 | 108778.76 KB | 94,961.17 | +| CsvHelper | .NET 7.0 | Row | 50000 | 68.558 ms | 9.26 | 33 | 486.8 | 1371.2 | 20.65 KB | 18.03 | +| Sep______ | .NET 8.0 | Row | 50000 | 6.773 ms | 0.91 | 33 | 4928.3 | 135.5 | 1.14 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Row | 50000 | 18.409 ms | 2.47 | 33 | 1813.1 | 368.2 | 7.2 KB | 6.28 | +| ReadLine_ | .NET 8.0 | Row | 50000 | 14.955 ms | 2.03 | 33 | 2231.9 | 299.1 | 108778.75 KB | 94,961.16 | +| CsvHelper | .NET 8.0 | Row | 50000 | 53.158 ms | 7.17 | 33 | 627.9 | 1063.2 | 20.6 KB | 17.98 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Cols | 50000 | 7.723 ms | 1.00 | 33 | 4321.6 | 154.5 | 1.15 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Cols | 50000 | 23.941 ms | 3.10 | 33 | 1394.2 | 478.8 | 7.33 KB | 6.40 | +| ReadLine_ | .NET 7.0 | Cols | 50000 | 16.261 ms | 2.11 | 33 | 2052.6 | 325.2 | 108778.75 KB | 94,880.28 | +| CsvHelper | .NET 7.0 | Cols | 50000 | 90.538 ms | 11.65 | 33 | 368.7 | 1810.8 | 446.31 KB | 389.29 | +| Sep______ | .NET 8.0 | Cols | 50000 | 7.323 ms | 0.95 | 33 | 4557.6 | 146.5 | 1.14 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Cols | 50000 | 21.064 ms | 2.73 | 33 | 1584.6 | 421.3 | 7.31 KB | 6.38 | +| ReadLine_ | .NET 8.0 | Cols | 50000 | 15.523 ms | 2.02 | 33 | 2150.2 | 310.5 | 108778.75 KB | 94,880.27 | +| CsvHelper | .NET 8.0 | Cols | 50000 | 84.033 ms | 10.81 | 33 | 397.2 | 1680.7 | 446.35 KB | 389.32 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Asset | 50000 | 38.130 ms | 1.00 | 33 | 875.4 | 762.6 | 13808.03 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Asset | 50000 | 61.626 ms | 1.62 | 33 | 541.6 | 1232.5 | 14025.04 KB | 1.02 | +| ReadLine_ | .NET 7.0 | Asset | 50000 | 125.779 ms | 3.33 | 33 | 265.4 | 2515.6 | 122304.12 KB | 8.86 | +| CsvHelper | .NET 7.0 | Asset | 50000 | 114.214 ms | 3.00 | 33 | 292.2 | 2284.3 | 13971.43 KB | 1.01 | +| Sep______ | .NET 8.0 | Asset | 50000 | 34.585 ms | 0.91 | 33 | 965.1 | 691.7 | 13808.01 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Asset | 50000 | 53.850 ms | 1.41 | 33 | 619.8 | 1077.0 | 14025.15 KB | 1.02 | +| ReadLine_ | .NET 8.0 | Asset | 50000 | 115.295 ms | 3.02 | 33 | 289.5 | 2305.9 | 122304.01 KB | 8.86 | +| CsvHelper | .NET 8.0 | Asset | 50000 | 99.115 ms | 2.60 | 33 | 336.8 | 1982.3 | 13970.79 KB | 1.01 | From e2bed48a03b7b3496b30e402dc2e64208dd10cb9 Mon Sep 17 00:00:00 2001 From: ntr Date: Sun, 20 Aug 2023 12:39:52 +0200 Subject: [PATCH 21/30] add initial xeon silver 4316 with AVX-512 benchmarks and use ProcessorBrandStringHelper --- .../FloatsReaderBench.md | 41 ++++++++++++++++++ .../PackageAssetsBench.md | 42 +++++++++++++++++++ .../PackageAssetsBenchQuotes.md | 42 +++++++++++++++++++ src/Sep.ComparisonBenchmarks/Program.cs | 6 ++- 4 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 benchmarks/Intel.Xeon.Silver.4316.CPU.@.2.30GHz/FloatsReaderBench.md create mode 100644 benchmarks/Intel.Xeon.Silver.4316.CPU.@.2.30GHz/PackageAssetsBench.md create mode 100644 benchmarks/Intel.Xeon.Silver.4316.CPU.@.2.30GHz/PackageAssetsBenchQuotes.md diff --git a/benchmarks/Intel.Xeon.Silver.4316.CPU.@.2.30GHz/FloatsReaderBench.md b/benchmarks/Intel.Xeon.Silver.4316.CPU.@.2.30GHz/FloatsReaderBench.md new file mode 100644 index 00000000..16c66a43 --- /dev/null +++ b/benchmarks/Intel.Xeon.Silver.4316.CPU.@.2.30GHz/FloatsReaderBench.md @@ -0,0 +1,41 @@ +``` ini + +BenchmarkDotNet=v0.13.5, OS=Windows 10 (10.0.17763.3287/1809/October2018Update/Redstone5) +Intel Xeon Silver 4316 CPU 2.30GHz, 1 CPU, 40 logical and 20 physical cores +.NET SDK=8.0.100-preview.7.23376.3 + [Host] : .NET 8.0.0 (8.0.23.37506), X64 RyuJIT AVX2 + Job-UHOMSO : .NET 7.0.10 (7.0.1023.36312), X64 RyuJIT AVX2 + Job-SRTOSO : .NET 8.0.0 (8.0.23.37506), X64 RyuJIT AVX2 + +InvocationCount=Default IterationTime=300.0000 ms MinIterationCount=5 +WarmupCount=6 Reader=String + +``` +| Method | Runtime | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | +|---------- |--------- |------- |------ |-----------:|------:|---:|-------:|--------:|------------:|------------:| +| Sep______ | .NET 7.0 | Row | 25000 | 5.417 ms | 1.00 | 27 | 5033.3 | 216.7 | 1.57 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Row | 25000 | 6.328 ms | 1.17 | 27 | 4308.3 | 253.1 | 10.56 KB | 6.74 | +| ReadLine_ | .NET 7.0 | Row | 25000 | 28.805 ms | 5.35 | 27 | 946.5 | 1152.2 | 89986.9 KB | 57,412.20 | +| CsvHelper | .NET 7.0 | Row | 25000 | 76.930 ms | 14.20 | 27 | 354.4 | 3077.2 | 20.74 KB | 13.23 | +| Sep______ | .NET 8.0 | Row | 25000 | 5.841 ms | 1.08 | 27 | 4667.7 | 233.6 | 1.72 KB | 1.10 | +| Sylvan___ | .NET 8.0 | Row | 25000 | 6.526 ms | 1.20 | 27 | 4177.8 | 261.0 | 10.56 KB | 6.74 | +| ReadLine_ | .NET 8.0 | Row | 25000 | 28.041 ms | 5.18 | 27 | 972.3 | 1121.7 | 89986.9 KB | 57,412.20 | +| CsvHelper | .NET 8.0 | Row | 25000 | 77.364 ms | 14.27 | 27 | 352.4 | 3094.5 | 20.77 KB | 13.25 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Cols | 25000 | 6.921 ms | 1.00 | 27 | 3939.4 | 276.8 | 1.57 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Cols | 25000 | 10.300 ms | 1.49 | 27 | 2647.0 | 412.0 | 10.58 KB | 6.72 | +| ReadLine_ | .NET 7.0 | Cols | 25000 | 29.077 ms | 4.19 | 27 | 937.6 | 1163.1 | 89986.9 KB | 57,198.38 | +| CsvHelper | .NET 7.0 | Cols | 25000 | 95.212 ms | 13.76 | 27 | 286.3 | 3808.5 | 28451.27 KB | 18,084.48 | +| Sep______ | .NET 8.0 | Cols | 25000 | 6.685 ms | 0.97 | 27 | 4078.0 | 267.4 | 1.73 KB | 1.10 | +| Sylvan___ | .NET 8.0 | Cols | 25000 | 9.724 ms | 1.41 | 27 | 2803.8 | 388.9 | 10.57 KB | 6.72 | +| ReadLine_ | .NET 8.0 | Cols | 25000 | 27.190 ms | 3.94 | 27 | 1002.7 | 1087.6 | 89986.89 KB | 57,198.37 | +| CsvHelper | .NET 8.0 | Cols | 25000 | 81.925 ms | 11.88 | 27 | 332.8 | 3277.0 | 28451.84 KB | 18,084.85 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Floats | 25000 | 61.789 ms | 1.00 | 27 | 441.2 | 2471.6 | 9.1 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Floats | 25000 | 146.737 ms | 2.37 | 27 | 185.8 | 5869.5 | 19.62 KB | 2.16 | +| ReadLine_ | .NET 7.0 | Floats | 25000 | 168.368 ms | 2.73 | 27 | 161.9 | 6734.7 | 89993.63 KB | 9,894.08 | +| CsvHelper | .NET 7.0 | Floats | 25000 | 264.441 ms | 4.28 | 27 | 103.1 | 10577.6 | 22039.48 KB | 2,423.07 | +| Sep______ | .NET 8.0 | Floats | 25000 | 44.122 ms | 0.71 | 27 | 617.9 | 1764.9 | 9.08 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Floats | 25000 | 135.504 ms | 2.19 | 27 | 201.2 | 5420.2 | 19.07 KB | 2.10 | +| ReadLine_ | .NET 8.0 | Floats | 25000 | 151.400 ms | 2.45 | 27 | 180.1 | 6056.0 | 89990.48 KB | 9,893.74 | +| CsvHelper | .NET 8.0 | Floats | 25000 | 231.426 ms | 3.75 | 27 | 117.8 | 9257.1 | 22036.58 KB | 2,422.75 | diff --git a/benchmarks/Intel.Xeon.Silver.4316.CPU.@.2.30GHz/PackageAssetsBench.md b/benchmarks/Intel.Xeon.Silver.4316.CPU.@.2.30GHz/PackageAssetsBench.md new file mode 100644 index 00000000..39e90d00 --- /dev/null +++ b/benchmarks/Intel.Xeon.Silver.4316.CPU.@.2.30GHz/PackageAssetsBench.md @@ -0,0 +1,42 @@ +``` ini + +BenchmarkDotNet=v0.13.5, OS=Windows 10 (10.0.17763.3287/1809/October2018Update/Redstone5) +Intel Xeon Silver 4316 CPU 2.30GHz, 1 CPU, 40 logical and 20 physical cores +.NET SDK=8.0.100-preview.7.23376.3 + [Host] : .NET 8.0.0 (8.0.23.37506), X64 RyuJIT AVX2 + Job-UHOMSO : .NET 7.0.10 (7.0.1023.36312), X64 RyuJIT AVX2 + Job-SRTOSO : .NET 8.0.0 (8.0.23.37506), X64 RyuJIT AVX2 + +InvocationCount=Default IterationTime=300.0000 ms MaxIterationCount=Default +MinIterationCount=5 WarmupCount=6 Quotes=False +Reader=String + +``` +| Method | Runtime | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | +|---------- |--------- |------ |------ |-----------:|------:|---:|-------:|-------:|-------------:|------------:| +| Sep______ | .NET 7.0 | Row | 50000 | 5.948 ms | 1.00 | 29 | 4905.8 | 119.0 | 1.14 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Row | 50000 | 6.733 ms | 1.13 | 29 | 4334.0 | 134.7 | 7.18 KB | 6.29 | +| ReadLine_ | .NET 7.0 | Row | 50000 | 27.988 ms | 4.70 | 29 | 1042.6 | 559.8 | 88608.29 KB | 77,617.53 | +| CsvHelper | .NET 7.0 | Row | 50000 | 114.902 ms | 19.31 | 29 | 254.0 | 2298.0 | 20.65 KB | 18.09 | +| Sep______ | .NET 8.0 | Row | 50000 | 5.440 ms | 0.91 | 29 | 5363.8 | 108.8 | 1.29 KB | 1.13 | +| Sylvan___ | .NET 8.0 | Row | 50000 | 6.383 ms | 1.07 | 29 | 4571.5 | 127.7 | 7.18 KB | 6.29 | +| ReadLine_ | .NET 8.0 | Row | 50000 | 26.933 ms | 4.53 | 29 | 1083.5 | 538.7 | 88608.26 KB | 77,617.50 | +| CsvHelper | .NET 8.0 | Row | 50000 | 90.332 ms | 15.18 | 29 | 323.0 | 1806.6 | 20.69 KB | 18.12 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Cols | 50000 | 7.401 ms | 1.00 | 29 | 3942.7 | 148.0 | 1.15 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Cols | 50000 | 11.545 ms | 1.56 | 29 | 2527.5 | 230.9 | 7.19 KB | 6.28 | +| ReadLine_ | .NET 7.0 | Cols | 50000 | 28.892 ms | 3.90 | 29 | 1010.0 | 577.8 | 88608.29 KB | 77,352.84 | +| CsvHelper | .NET 7.0 | Cols | 50000 | 157.705 ms | 21.31 | 29 | 185.0 | 3154.1 | 446.5 KB | 389.78 | +| Sep______ | .NET 8.0 | Cols | 50000 | 6.683 ms | 0.90 | 29 | 4366.8 | 133.7 | 1.3 KB | 1.13 | +| Sylvan___ | .NET 8.0 | Cols | 50000 | 10.417 ms | 1.41 | 29 | 2801.2 | 208.3 | 7.19 KB | 6.28 | +| ReadLine_ | .NET 8.0 | Cols | 50000 | 27.292 ms | 3.69 | 29 | 1069.2 | 545.8 | 88608.26 KB | 77,352.82 | +| CsvHelper | .NET 8.0 | Cols | 50000 | 141.559 ms | 19.11 | 29 | 206.1 | 2831.2 | 446.45 KB | 389.74 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Asset | 50000 | 58.708 ms | 1.00 | 29 | 497.1 | 1174.2 | 13799.65 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Asset | 50000 | 76.436 ms | 1.31 | 29 | 381.8 | 1528.7 | 14025.71 KB | 1.02 | +| ReadLine_ | .NET 7.0 | Asset | 50000 | 174.574 ms | 3.00 | 29 | 167.2 | 3491.5 | 102133.35 KB | 7.40 | +| CsvHelper | .NET 7.0 | Asset | 50000 | 172.747 ms | 2.95 | 29 | 168.9 | 3454.9 | 13970.85 KB | 1.01 | +| Sep______ | .NET 8.0 | Asset | 50000 | 55.672 ms | 0.95 | 29 | 524.2 | 1113.4 | 13800.53 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Asset | 50000 | 71.428 ms | 1.22 | 29 | 408.5 | 1428.6 | 14026.38 KB | 1.02 | +| ReadLine_ | .NET 8.0 | Asset | 50000 | 162.203 ms | 2.76 | 29 | 179.9 | 3244.1 | 102133.69 KB | 7.40 | +| CsvHelper | .NET 8.0 | Asset | 50000 | 161.805 ms | 2.76 | 29 | 180.3 | 3236.1 | 13970.8 KB | 1.01 | diff --git a/benchmarks/Intel.Xeon.Silver.4316.CPU.@.2.30GHz/PackageAssetsBenchQuotes.md b/benchmarks/Intel.Xeon.Silver.4316.CPU.@.2.30GHz/PackageAssetsBenchQuotes.md new file mode 100644 index 00000000..8d9d93c6 --- /dev/null +++ b/benchmarks/Intel.Xeon.Silver.4316.CPU.@.2.30GHz/PackageAssetsBenchQuotes.md @@ -0,0 +1,42 @@ +``` ini + +BenchmarkDotNet=v0.13.5, OS=Windows 10 (10.0.17763.3287/1809/October2018Update/Redstone5) +Intel Xeon Silver 4316 CPU 2.30GHz, 1 CPU, 40 logical and 20 physical cores +.NET SDK=8.0.100-preview.7.23376.3 + [Host] : .NET 8.0.0 (8.0.23.37506), X64 RyuJIT AVX2 + Job-UHOMSO : .NET 7.0.10 (7.0.1023.36312), X64 RyuJIT AVX2 + Job-SRTOSO : .NET 8.0.0 (8.0.23.37506), X64 RyuJIT AVX2 + +InvocationCount=Default IterationTime=300.0000 ms MaxIterationCount=Default +MinIterationCount=5 WarmupCount=6 Quotes=True +Reader=String + +``` +| Method | Runtime | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | +|---------- |--------- |------ |------ |----------:|------:|---:|-------:|-------:|-------------:|------------:| +| Sep______ | .NET 7.0 | Row | 50000 | 15.13 ms | 1.00 | 33 | 2206.5 | 302.5 | 1.17 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Row | 50000 | 42.25 ms | 2.80 | 33 | 790.0 | 845.0 | 7.26 KB | 6.22 | +| ReadLine_ | .NET 7.0 | Row | 50000 | 32.95 ms | 2.18 | 33 | 1013.0 | 659.0 | 108778.78 KB | 93,135.01 | +| CsvHelper | .NET 7.0 | Row | 50000 | 121.55 ms | 8.03 | 33 | 274.6 | 2431.1 | 20.84 KB | 17.84 | +| Sep______ | .NET 8.0 | Row | 50000 | 12.34 ms | 0.82 | 33 | 2705.0 | 246.8 | 1.31 KB | 1.12 | +| Sylvan___ | .NET 8.0 | Row | 50000 | 35.42 ms | 2.34 | 33 | 942.4 | 708.4 | 7.24 KB | 6.20 | +| ReadLine_ | .NET 8.0 | Row | 50000 | 32.15 ms | 2.13 | 33 | 1038.3 | 642.9 | 108778.77 KB | 93,135.00 | +| CsvHelper | .NET 8.0 | Row | 50000 | 104.02 ms | 6.88 | 33 | 320.9 | 2080.4 | 20.69 KB | 17.72 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Cols | 50000 | 15.80 ms | 1.00 | 33 | 2112.6 | 316.0 | 1.18 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Cols | 50000 | 45.83 ms | 2.91 | 33 | 728.3 | 916.6 | 7.33 KB | 6.24 | +| ReadLine_ | .NET 7.0 | Cols | 50000 | 33.98 ms | 2.15 | 33 | 982.2 | 679.7 | 108778.78 KB | 92,516.17 | +| CsvHelper | .NET 7.0 | Cols | 50000 | 177.61 ms | 11.23 | 33 | 187.9 | 3552.2 | 446.43 KB | 379.69 | +| Sep______ | .NET 8.0 | Cols | 50000 | 15.59 ms | 0.99 | 33 | 2140.6 | 311.8 | 1.5 KB | 1.28 | +| Sylvan___ | .NET 8.0 | Cols | 50000 | 38.85 ms | 2.46 | 33 | 859.2 | 777.0 | 7.25 KB | 6.16 | +| ReadLine_ | .NET 8.0 | Cols | 50000 | 32.64 ms | 2.06 | 33 | 1022.6 | 652.8 | 108778.77 KB | 92,516.16 | +| CsvHelper | .NET 8.0 | Cols | 50000 | 161.84 ms | 10.23 | 33 | 206.2 | 3236.9 | 446.45 KB | 379.70 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Asset | 50000 | 71.19 ms | 1.00 | 33 | 468.9 | 1423.8 | 13808.03 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Asset | 50000 | 106.82 ms | 1.50 | 33 | 312.5 | 2136.5 | 14025.33 KB | 1.02 | +| ReadLine_ | .NET 7.0 | Asset | 50000 | 205.79 ms | 2.89 | 33 | 162.2 | 4115.9 | 122304.11 KB | 8.86 | +| CsvHelper | .NET 7.0 | Asset | 50000 | 192.54 ms | 2.71 | 33 | 173.3 | 3850.9 | 13970.85 KB | 1.01 | +| Sep______ | .NET 8.0 | Asset | 50000 | 52.18 ms | 0.74 | 33 | 639.6 | 1043.7 | 13808.73 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Asset | 50000 | 96.05 ms | 1.35 | 33 | 347.5 | 1921.0 | 14026.75 KB | 1.02 | +| ReadLine_ | .NET 8.0 | Asset | 50000 | 202.80 ms | 2.82 | 33 | 164.6 | 4056.0 | 122304.21 KB | 8.86 | +| CsvHelper | .NET 8.0 | Asset | 50000 | 179.61 ms | 2.52 | 33 | 185.8 | 3592.1 | 13970.8 KB | 1.01 | diff --git a/src/Sep.ComparisonBenchmarks/Program.cs b/src/Sep.ComparisonBenchmarks/Program.cs index df4b430e..eaeb4c40 100644 --- a/src/Sep.ComparisonBenchmarks/Program.cs +++ b/src/Sep.ComparisonBenchmarks/Program.cs @@ -9,6 +9,7 @@ using System.Threading; using BenchmarkDotNet.Columns; using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Environments; using BenchmarkDotNet.Exporters; using BenchmarkDotNet.Jobs; using BenchmarkDotNet.Loggers; @@ -64,8 +65,9 @@ foreach (var s in summaries) { var cpuInfo = s.HostEnvironmentInfo.CpuInfo.Value; - var processorName = cpuInfo.ProcessorName; - var processorNameInDirectory = processorName.Replace(" Processor", "").Replace(" ", "."); + var processorName = ProcessorBrandStringHelper.Prettify(cpuInfo); + var processorNameInDirectory = processorName + .Replace(" Processor", "").Replace(" ", "."); var sourceDirectory = GetSourceDirectory(); var directory = $"{sourceDirectory}/../../benchmarks/{processorNameInDirectory}"; From 2586c8c2ec23fa280d8027ef7bffdeedf81a1b59 Mon Sep 17 00:00:00 2001 From: ntr Date: Sun, 20 Aug 2023 14:24:46 +0200 Subject: [PATCH 22/30] rename 4316 bench --- .../FloatsReaderBench.md | 0 .../PackageAssetsBench.md | 0 .../PackageAssetsBenchQuotes.md | 0 src/Sep.ComparisonBenchmarks/Program.cs | 3 ++- 4 files changed, 2 insertions(+), 1 deletion(-) rename benchmarks/{Intel.Xeon.Silver.4316.CPU.@.2.30GHz => Intel.Xeon.Silver.4316.2.30GHz}/FloatsReaderBench.md (100%) rename benchmarks/{Intel.Xeon.Silver.4316.CPU.@.2.30GHz => Intel.Xeon.Silver.4316.2.30GHz}/PackageAssetsBench.md (100%) rename benchmarks/{Intel.Xeon.Silver.4316.CPU.@.2.30GHz => Intel.Xeon.Silver.4316.2.30GHz}/PackageAssetsBenchQuotes.md (100%) diff --git a/benchmarks/Intel.Xeon.Silver.4316.CPU.@.2.30GHz/FloatsReaderBench.md b/benchmarks/Intel.Xeon.Silver.4316.2.30GHz/FloatsReaderBench.md similarity index 100% rename from benchmarks/Intel.Xeon.Silver.4316.CPU.@.2.30GHz/FloatsReaderBench.md rename to benchmarks/Intel.Xeon.Silver.4316.2.30GHz/FloatsReaderBench.md diff --git a/benchmarks/Intel.Xeon.Silver.4316.CPU.@.2.30GHz/PackageAssetsBench.md b/benchmarks/Intel.Xeon.Silver.4316.2.30GHz/PackageAssetsBench.md similarity index 100% rename from benchmarks/Intel.Xeon.Silver.4316.CPU.@.2.30GHz/PackageAssetsBench.md rename to benchmarks/Intel.Xeon.Silver.4316.2.30GHz/PackageAssetsBench.md diff --git a/benchmarks/Intel.Xeon.Silver.4316.CPU.@.2.30GHz/PackageAssetsBenchQuotes.md b/benchmarks/Intel.Xeon.Silver.4316.2.30GHz/PackageAssetsBenchQuotes.md similarity index 100% rename from benchmarks/Intel.Xeon.Silver.4316.CPU.@.2.30GHz/PackageAssetsBenchQuotes.md rename to benchmarks/Intel.Xeon.Silver.4316.2.30GHz/PackageAssetsBenchQuotes.md diff --git a/src/Sep.ComparisonBenchmarks/Program.cs b/src/Sep.ComparisonBenchmarks/Program.cs index eaeb4c40..231531a5 100644 --- a/src/Sep.ComparisonBenchmarks/Program.cs +++ b/src/Sep.ComparisonBenchmarks/Program.cs @@ -67,7 +67,8 @@ var cpuInfo = s.HostEnvironmentInfo.CpuInfo.Value; var processorName = ProcessorBrandStringHelper.Prettify(cpuInfo); var processorNameInDirectory = processorName - .Replace(" Processor", "").Replace(" ", "."); + .Replace(" Processor", "").Replace(" CPU", "").Replace(" ", "."); + log(processorName); var sourceDirectory = GetSourceDirectory(); var directory = $"{sourceDirectory}/../../benchmarks/{processorNameInDirectory}"; From 36e7a8d04d8e11474984128748a2ef0dc3f4cfce Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 25 Aug 2023 13:04:07 +0200 Subject: [PATCH 23/30] add Versions.txt to benchmarks --- .../FloatsReaderBench.md | 0 .../PackageAssetsBench.md | 0 .../PackageAssetsBenchQuotes.md | 0 benchmarks/AMD.Ryzen.9.5950X/Versions.txt | 1 + .../Versions.txt | 1 + src/Sep.ComparisonBenchmarks/Program.cs | 24 +++++++++++++++---- 6 files changed, 21 insertions(+), 5 deletions(-) rename benchmarks/{AMD.Ryzen.9.5950X.16-Core => AMD.Ryzen.9.5950X}/FloatsReaderBench.md (100%) rename benchmarks/{AMD.Ryzen.9.5950X.16-Core => AMD.Ryzen.9.5950X}/PackageAssetsBench.md (100%) rename benchmarks/{AMD.Ryzen.9.5950X.16-Core => AMD.Ryzen.9.5950X}/PackageAssetsBenchQuotes.md (100%) create mode 100644 benchmarks/AMD.Ryzen.9.5950X/Versions.txt create mode 100644 benchmarks/Intel.Xeon.Silver.4316.2.30GHz/Versions.txt diff --git a/benchmarks/AMD.Ryzen.9.5950X.16-Core/FloatsReaderBench.md b/benchmarks/AMD.Ryzen.9.5950X/FloatsReaderBench.md similarity index 100% rename from benchmarks/AMD.Ryzen.9.5950X.16-Core/FloatsReaderBench.md rename to benchmarks/AMD.Ryzen.9.5950X/FloatsReaderBench.md diff --git a/benchmarks/AMD.Ryzen.9.5950X.16-Core/PackageAssetsBench.md b/benchmarks/AMD.Ryzen.9.5950X/PackageAssetsBench.md similarity index 100% rename from benchmarks/AMD.Ryzen.9.5950X.16-Core/PackageAssetsBench.md rename to benchmarks/AMD.Ryzen.9.5950X/PackageAssetsBench.md diff --git a/benchmarks/AMD.Ryzen.9.5950X.16-Core/PackageAssetsBenchQuotes.md b/benchmarks/AMD.Ryzen.9.5950X/PackageAssetsBenchQuotes.md similarity index 100% rename from benchmarks/AMD.Ryzen.9.5950X.16-Core/PackageAssetsBenchQuotes.md rename to benchmarks/AMD.Ryzen.9.5950X/PackageAssetsBenchQuotes.md diff --git a/benchmarks/AMD.Ryzen.9.5950X/Versions.txt b/benchmarks/AMD.Ryzen.9.5950X/Versions.txt new file mode 100644 index 00000000..11d4ffb1 --- /dev/null +++ b/benchmarks/AMD.Ryzen.9.5950X/Versions.txt @@ -0,0 +1 @@ +Sep 0.2.3, Sylvan 1.3.2.0, CsvHelper 30.0.1.0 \ No newline at end of file diff --git a/benchmarks/Intel.Xeon.Silver.4316.2.30GHz/Versions.txt b/benchmarks/Intel.Xeon.Silver.4316.2.30GHz/Versions.txt new file mode 100644 index 00000000..11d4ffb1 --- /dev/null +++ b/benchmarks/Intel.Xeon.Silver.4316.2.30GHz/Versions.txt @@ -0,0 +1 @@ +Sep 0.2.3, Sylvan 1.3.2.0, CsvHelper 30.0.1.0 \ No newline at end of file diff --git a/src/Sep.ComparisonBenchmarks/Program.cs b/src/Sep.ComparisonBenchmarks/Program.cs index 231531a5..2381aa50 100644 --- a/src/Sep.ComparisonBenchmarks/Program.cs +++ b/src/Sep.ComparisonBenchmarks/Program.cs @@ -5,25 +5,28 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Reflection; using System.Runtime.CompilerServices; using System.Threading; using BenchmarkDotNet.Columns; using BenchmarkDotNet.Configs; using BenchmarkDotNet.Environments; using BenchmarkDotNet.Exporters; -using BenchmarkDotNet.Jobs; using BenchmarkDotNet.Loggers; using BenchmarkDotNet.Parameters; using BenchmarkDotNet.Reports; using BenchmarkDotNet.Running; using nietras.SeparatedValues.ComparisonBenchmarks; +#if DEBUG +using BenchmarkDotNet.Jobs; using Perfolizer.Horology; +#endif [assembly: System.Runtime.InteropServices.ComVisible(false)] Action log = t => { Console.WriteLine(t); Trace.WriteLine(t); }; -log($"{Environment.Version} args: {args.Length}"); +log($"{Environment.Version} args: {args.Length} versions: {GetVersions()}"); await PackageAssetsTestData.EnsurePackageAssets().ConfigureAwait(true); @@ -55,9 +58,9 @@ var nameToBenchTypesSet = new Dictionary() { - { nameof(PackageAssetsBench), new[] { typeof(RowPackageAssetsBench), typeof(ColsPackageAssetsBench), typeof(AssetPackageAssetsBench), } }, - { nameof(PackageAssetsBench) + "Quotes", new[] { typeof(QuotesRowPackageAssetsBench), typeof(QuotesColsPackageAssetsBench), typeof(QuotesAssetPackageAssetsBench), } }, - { nameof(FloatsReaderBench), new[] { typeof(RowFloatsReaderBench), typeof(ColsFloatsReaderBench), typeof(FloatsFloatsReaderBench), } }, + { nameof(PackageAssetsBench), new[] { typeof(RowPackageAssetsBench), /*typeof(ColsPackageAssetsBench), typeof(AssetPackageAssetsBench), */} }, + //{ nameof(PackageAssetsBench) + "Quotes", new[] { typeof(QuotesRowPackageAssetsBench), typeof(QuotesColsPackageAssetsBench), typeof(QuotesAssetPackageAssetsBench), } }, + //{ nameof(FloatsReaderBench), new[] { typeof(RowFloatsReaderBench), typeof(ColsFloatsReaderBench), typeof(FloatsFloatsReaderBench), } }, }; foreach (var (name, benchTypes) in nameToBenchTypesSet) { @@ -87,6 +90,9 @@ var text = reader.ReadToEnd(); text = text.Replace("**", ""); File.WriteAllText(filePath, text); + + var versions = GetVersions(); + File.WriteAllText(Path.Combine(directory, "Versions.txt"), versions); } } } @@ -135,4 +141,12 @@ static long BytesFromReaderSpec(IReadOnlyList parameters) return parameters.Select(p => p.Value as ReaderSpec).Where(r => r is not null).Single()!.Bytes; } +static string GetVersions() => + $"Sep {GetInformationalVersion(typeof(nietras.SeparatedValues.SepReader).Assembly)}, " + + $"Sylvan {GetInformationalVersion(typeof(Sylvan.Data.Csv.CsvDataReader).Assembly)}, " + + $"CsvHelper {GetInformationalVersion(typeof(CsvHelper.CsvReader).Assembly)}"; + +static string GetInformationalVersion(Assembly assembly) => + FileVersionInfo.GetVersionInfo(assembly.Location).FileVersion!; + static string GetSourceDirectory([CallerFilePath] string filePath = "") => Path.GetDirectoryName(filePath)!; From 9e413ff5f9022457502c04dec5ba2144f9dfa280 Mon Sep 17 00:00:00 2001 From: ntr Date: Sat, 26 Aug 2023 11:11:10 +0200 Subject: [PATCH 24/30] reactivate all benchs --- src/Sep.ComparisonBenchmarks/Program.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Sep.ComparisonBenchmarks/Program.cs b/src/Sep.ComparisonBenchmarks/Program.cs index 2381aa50..e85e8c01 100644 --- a/src/Sep.ComparisonBenchmarks/Program.cs +++ b/src/Sep.ComparisonBenchmarks/Program.cs @@ -58,9 +58,9 @@ var nameToBenchTypesSet = new Dictionary() { - { nameof(PackageAssetsBench), new[] { typeof(RowPackageAssetsBench), /*typeof(ColsPackageAssetsBench), typeof(AssetPackageAssetsBench), */} }, - //{ nameof(PackageAssetsBench) + "Quotes", new[] { typeof(QuotesRowPackageAssetsBench), typeof(QuotesColsPackageAssetsBench), typeof(QuotesAssetPackageAssetsBench), } }, - //{ nameof(FloatsReaderBench), new[] { typeof(RowFloatsReaderBench), typeof(ColsFloatsReaderBench), typeof(FloatsFloatsReaderBench), } }, + { nameof(PackageAssetsBench), new[] { typeof(RowPackageAssetsBench), typeof(ColsPackageAssetsBench), typeof(AssetPackageAssetsBench), } }, + { nameof(PackageAssetsBench) + "Quotes", new[] { typeof(QuotesRowPackageAssetsBench), typeof(QuotesColsPackageAssetsBench), typeof(QuotesAssetPackageAssetsBench), } }, + { nameof(FloatsReaderBench), new[] { typeof(RowFloatsReaderBench), typeof(ColsFloatsReaderBench), typeof(FloatsFloatsReaderBench), } }, }; foreach (var (name, benchTypes) in nameToBenchTypesSet) { From c0b7930adffb3a47f31d5b8fcd70997b1180a6f2 Mon Sep 17 00:00:00 2001 From: ntr Date: Sat, 26 Aug 2023 11:32:20 +0200 Subject: [PATCH 25/30] add Neoverse.N1 benchmarks --- benchmarks/Neoverse.N1/FloatsReaderBench.md | 41 ++++++++++++++++++ benchmarks/Neoverse.N1/PackageAssetsBench.md | 42 +++++++++++++++++++ .../Neoverse.N1/PackageAssetsBenchQuotes.md | 42 +++++++++++++++++++ benchmarks/Neoverse.N1/Versions.txt | 1 + 4 files changed, 126 insertions(+) create mode 100644 benchmarks/Neoverse.N1/FloatsReaderBench.md create mode 100644 benchmarks/Neoverse.N1/PackageAssetsBench.md create mode 100644 benchmarks/Neoverse.N1/PackageAssetsBenchQuotes.md create mode 100644 benchmarks/Neoverse.N1/Versions.txt diff --git a/benchmarks/Neoverse.N1/FloatsReaderBench.md b/benchmarks/Neoverse.N1/FloatsReaderBench.md new file mode 100644 index 00000000..57d0902c --- /dev/null +++ b/benchmarks/Neoverse.N1/FloatsReaderBench.md @@ -0,0 +1,41 @@ +``` ini + +BenchmarkDotNet=v0.13.5, OS=ubuntu 22.04 +Unknown processor +.NET SDK=8.0.100-preview.7.23376.3 + [Host] : .NET 8.0.0 (8.0.23.37506), Arm64 RyuJIT AdvSIMD + Job-GDSTLJ : .NET 7.0.10 (7.0.1023.36801), Arm64 RyuJIT AdvSIMD + Job-WFSLTV : .NET 8.0.0 (8.0.23.37506), Arm64 RyuJIT AdvSIMD + +InvocationCount=Default IterationTime=300.0000 ms MinIterationCount=5 +WarmupCount=6 Reader=String + +``` +| Method | Runtime | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | +|---------- |--------- |------- |------ |----------:|------:|---:|-------:|--------:|------------:|------------:| +| Sep______ | .NET 7.0 | Row | 25000 | 11.54 ms | 1.00 | 27 | 2359.4 | 461.4 | 1.54 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Row | 25000 | 37.00 ms | 3.21 | 27 | 735.6 | 1479.9 | 10.48 KB | 6.80 | +| ReadLine_ | .NET 7.0 | Row | 25000 | 40.34 ms | 3.50 | 27 | 674.7 | 1613.6 | 89986.96 KB | 58,394.58 | +| CsvHelper | .NET 7.0 | Row | 25000 | 84.31 ms | 7.31 | 27 | 322.8 | 3372.4 | 20.82 KB | 13.51 | +| Sep______ | .NET 8.0 | Row | 25000 | 11.63 ms | 1.01 | 27 | 2339.4 | 465.3 | 1.54 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Row | 25000 | 38.26 ms | 3.32 | 27 | 711.3 | 1530.4 | 10.3 KB | 6.69 | +| ReadLine_ | .NET 8.0 | Row | 25000 | 40.77 ms | 3.53 | 27 | 667.5 | 1630.8 | 89987.06 KB | 58,394.64 | +| CsvHelper | .NET 8.0 | Row | 25000 | 79.69 ms | 6.91 | 27 | 341.5 | 3187.7 | 20.86 KB | 13.53 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Cols | 25000 | 13.37 ms | 1.00 | 27 | 2035.0 | 535.0 | 1.55 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Cols | 25000 | 41.82 ms | 3.13 | 27 | 650.8 | 1672.8 | 10.48 KB | 6.74 | +| ReadLine_ | .NET 7.0 | Cols | 25000 | 42.16 ms | 3.15 | 27 | 645.5 | 1686.4 | 89986.99 KB | 57,881.08 | +| CsvHelper | .NET 7.0 | Cols | 25000 | 90.73 ms | 6.79 | 27 | 300.0 | 3629.2 | 28451.35 KB | 18,300.37 | +| Sep______ | .NET 8.0 | Cols | 25000 | 13.74 ms | 1.03 | 27 | 1980.9 | 549.6 | 1.55 KB | 0.99 | +| Sylvan___ | .NET 8.0 | Cols | 25000 | 42.55 ms | 3.18 | 27 | 639.7 | 1701.9 | 10.33 KB | 6.64 | +| ReadLine_ | .NET 8.0 | Cols | 25000 | 38.88 ms | 2.90 | 27 | 700.0 | 1555.1 | 89987.06 KB | 57,881.12 | +| CsvHelper | .NET 8.0 | Cols | 25000 | 85.89 ms | 6.42 | 27 | 316.9 | 3435.7 | 28451.39 KB | 18,300.39 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Floats | 25000 | 64.82 ms | 1.00 | 27 | 419.9 | 2592.6 | 9.12 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Floats | 25000 | 209.21 ms | 3.23 | 27 | 130.1 | 8368.4 | 19.55 KB | 2.15 | +| ReadLine_ | .NET 7.0 | Floats | 25000 | 214.76 ms | 3.31 | 27 | 126.7 | 8590.6 | 89994.37 KB | 9,872.96 | +| CsvHelper | .NET 7.0 | Floats | 25000 | 297.94 ms | 4.60 | 27 | 91.3 | 11917.5 | 22040.05 KB | 2,417.94 | +| Sep______ | .NET 8.0 | Floats | 25000 | 53.37 ms | 0.82 | 27 | 510.0 | 2134.7 | 8.95 KB | 0.98 | +| Sylvan___ | .NET 8.0 | Floats | 25000 | 164.95 ms | 2.55 | 27 | 165.0 | 6598.0 | 18.84 KB | 2.07 | +| ReadLine_ | .NET 8.0 | Floats | 25000 | 160.20 ms | 2.47 | 27 | 169.9 | 6408.1 | 89990.64 KB | 9,872.55 | +| CsvHelper | .NET 8.0 | Floats | 25000 | 231.15 ms | 3.57 | 27 | 117.7 | 9245.8 | 22037.14 KB | 2,417.62 | diff --git a/benchmarks/Neoverse.N1/PackageAssetsBench.md b/benchmarks/Neoverse.N1/PackageAssetsBench.md new file mode 100644 index 00000000..13fd3067 --- /dev/null +++ b/benchmarks/Neoverse.N1/PackageAssetsBench.md @@ -0,0 +1,42 @@ +``` ini + +BenchmarkDotNet=v0.13.5, OS=ubuntu 22.04 +Unknown processor +.NET SDK=8.0.100-preview.7.23376.3 + [Host] : .NET 8.0.0 (8.0.23.37506), Arm64 RyuJIT AdvSIMD + Job-GDSTLJ : .NET 7.0.10 (7.0.1023.36801), Arm64 RyuJIT AdvSIMD + Job-WFSLTV : .NET 8.0.0 (8.0.23.37506), Arm64 RyuJIT AdvSIMD + +InvocationCount=Default IterationTime=300.0000 ms MaxIterationCount=Default +MinIterationCount=5 WarmupCount=6 Quotes=False +Reader=String + +``` +| Method | Runtime | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | +|---------- |--------- |------ |------ |----------:|------:|---:|-------:|-------:|-------------:|------------:| +| Sep______ | .NET 7.0 | Row | 50000 | 12.15 ms | 1.00 | 29 | 2393.9 | 243.0 | 1.11 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Row | 50000 | 34.31 ms | 2.82 | 29 | 847.7 | 686.2 | 6.25 KB | 5.64 | +| ReadLine_ | .NET 7.0 | Row | 50000 | 40.99 ms | 3.37 | 29 | 709.6 | 819.8 | 88608.34 KB | 79,942.68 | +| CsvHelper | .NET 7.0 | Row | 50000 | 107.97 ms | 8.89 | 29 | 269.4 | 2159.4 | 20.74 KB | 18.71 | +| Sep______ | .NET 8.0 | Row | 50000 | 12.01 ms | 0.99 | 29 | 2421.2 | 240.3 | 1.1 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Row | 50000 | 30.14 ms | 2.48 | 29 | 965.0 | 602.8 | 6.09 KB | 5.50 | +| ReadLine_ | .NET 8.0 | Row | 50000 | 39.05 ms | 3.21 | 29 | 744.9 | 780.9 | 88608.41 KB | 79,942.74 | +| CsvHelper | .NET 8.0 | Row | 50000 | 91.57 ms | 7.54 | 29 | 317.6 | 1831.5 | 20.77 KB | 18.74 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Cols | 50000 | 14.52 ms | 1.00 | 29 | 2002.8 | 290.5 | 1.12 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Cols | 50000 | 40.36 ms | 2.78 | 29 | 720.6 | 807.2 | 6.25 KB | 5.57 | +| ReadLine_ | .NET 7.0 | Cols | 50000 | 41.92 ms | 2.89 | 29 | 693.8 | 838.5 | 88608.36 KB | 78,899.97 | +| CsvHelper | .NET 7.0 | Cols | 50000 | 156.03 ms | 10.74 | 29 | 186.4 | 3120.6 | 446.66 KB | 397.72 | +| Sep______ | .NET 8.0 | Cols | 50000 | 14.24 ms | 0.98 | 29 | 2042.8 | 284.8 | 1.11 KB | 0.99 | +| Sylvan___ | .NET 8.0 | Cols | 50000 | 35.23 ms | 2.43 | 29 | 825.6 | 704.6 | 6.11 KB | 5.44 | +| ReadLine_ | .NET 8.0 | Cols | 50000 | 37.10 ms | 2.55 | 29 | 784.0 | 742.0 | 88608.32 KB | 78,899.93 | +| CsvHelper | .NET 8.0 | Cols | 50000 | 138.20 ms | 9.52 | 29 | 210.5 | 2763.9 | 446.61 KB | 397.68 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Asset | 50000 | 70.16 ms | 1.00 | 29 | 414.5 | 1403.3 | 13800.75 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Asset | 50000 | 107.28 ms | 1.53 | 29 | 271.1 | 2145.6 | 14025.09 KB | 1.02 | +| ReadLine_ | .NET 7.0 | Asset | 50000 | 159.87 ms | 2.27 | 29 | 181.9 | 3197.4 | 102134.11 KB | 7.40 | +| CsvHelper | .NET 7.0 | Asset | 50000 | 189.44 ms | 2.69 | 29 | 153.5 | 3788.8 | 13973.66 KB | 1.01 | +| Sep______ | .NET 8.0 | Asset | 50000 | 67.72 ms | 0.96 | 29 | 429.5 | 1354.3 | 13800.73 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Asset | 50000 | 100.09 ms | 1.43 | 29 | 290.6 | 2001.8 | 14024.23 KB | 1.02 | +| ReadLine_ | .NET 8.0 | Asset | 50000 | 144.19 ms | 2.06 | 29 | 201.7 | 2883.8 | 102134.74 KB | 7.40 | +| CsvHelper | .NET 8.0 | Asset | 50000 | 170.81 ms | 2.43 | 29 | 170.3 | 3416.1 | 13971.32 KB | 1.01 | diff --git a/benchmarks/Neoverse.N1/PackageAssetsBenchQuotes.md b/benchmarks/Neoverse.N1/PackageAssetsBenchQuotes.md new file mode 100644 index 00000000..23c80843 --- /dev/null +++ b/benchmarks/Neoverse.N1/PackageAssetsBenchQuotes.md @@ -0,0 +1,42 @@ +``` ini + +BenchmarkDotNet=v0.13.5, OS=ubuntu 22.04 +Unknown processor +.NET SDK=8.0.100-preview.7.23376.3 + [Host] : .NET 8.0.0 (8.0.23.37506), Arm64 RyuJIT AdvSIMD + Job-GDSTLJ : .NET 7.0.10 (7.0.1023.36801), Arm64 RyuJIT AdvSIMD + Job-WFSLTV : .NET 8.0.0 (8.0.23.37506), Arm64 RyuJIT AdvSIMD + +InvocationCount=Default IterationTime=300.0000 ms MaxIterationCount=Default +MinIterationCount=5 WarmupCount=6 Quotes=True +Reader=String + +``` +| Method | Runtime | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | +|---------- |--------- |------ |------ |----------:|------:|---:|-------:|-------:|-------------:|------------:| +| Sep______ | .NET 7.0 | Row | 50000 | 25.47 ms | 1.00 | 33 | 1306.5 | 509.5 | 1.39 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Row | 50000 | 46.21 ms | 1.81 | 33 | 720.2 | 924.2 | 6.25 KB | 4.50 | +| ReadLine_ | .NET 7.0 | Row | 50000 | 49.46 ms | 1.94 | 33 | 673.0 | 989.1 | 108778.86 KB | 78,333.02 | +| CsvHelper | .NET 7.0 | Row | 50000 | 121.28 ms | 4.76 | 33 | 274.4 | 2425.6 | 20.74 KB | 14.93 | +| Sep______ | .NET 8.0 | Row | 50000 | 23.43 ms | 0.92 | 33 | 1420.5 | 468.6 | 1.36 KB | 0.98 | +| Sylvan___ | .NET 8.0 | Row | 50000 | 39.42 ms | 1.55 | 33 | 844.2 | 788.5 | 6.11 KB | 4.40 | +| ReadLine_ | .NET 8.0 | Row | 50000 | 47.68 ms | 1.87 | 33 | 698.1 | 953.5 | 108778.91 KB | 78,333.05 | +| CsvHelper | .NET 8.0 | Row | 50000 | 107.00 ms | 4.20 | 33 | 311.0 | 2140.1 | 20.77 KB | 14.96 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Cols | 50000 | 28.30 ms | 1.00 | 33 | 1175.9 | 566.1 | 1.39 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Cols | 50000 | 53.39 ms | 1.89 | 33 | 623.4 | 1067.8 | 6.25 KB | 4.50 | +| ReadLine_ | .NET 7.0 | Cols | 50000 | 50.71 ms | 1.79 | 33 | 656.3 | 1014.2 | 108778.93 KB | 78,333.07 | +| CsvHelper | .NET 7.0 | Cols | 50000 | 180.08 ms | 6.36 | 33 | 184.8 | 3601.5 | 446.66 KB | 321.65 | +| Sep______ | .NET 8.0 | Cols | 50000 | 25.68 ms | 0.91 | 33 | 1295.8 | 513.7 | 1.36 KB | 0.98 | +| Sylvan___ | .NET 8.0 | Cols | 50000 | 45.33 ms | 1.61 | 33 | 734.2 | 906.6 | 6.15 KB | 4.43 | +| ReadLine_ | .NET 8.0 | Cols | 50000 | 44.96 ms | 1.59 | 33 | 740.3 | 899.2 | 108778.91 KB | 78,333.05 | +| CsvHelper | .NET 8.0 | Cols | 50000 | 153.04 ms | 5.41 | 33 | 217.5 | 3060.7 | 446.61 KB | 321.61 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Asset | 50000 | 88.20 ms | 1.00 | 33 | 377.4 | 1764.0 | 13808.62 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Asset | 50000 | 115.22 ms | 1.31 | 33 | 288.9 | 2304.4 | 14024.52 KB | 1.02 | +| ReadLine_ | .NET 7.0 | Asset | 50000 | 200.14 ms | 2.28 | 33 | 166.3 | 4002.9 | 122305.55 KB | 8.86 | +| CsvHelper | .NET 7.0 | Asset | 50000 | 208.19 ms | 2.35 | 33 | 159.9 | 4163.8 | 13971.42 KB | 1.01 | +| Sep______ | .NET 8.0 | Asset | 50000 | 84.89 ms | 0.96 | 33 | 392.1 | 1697.7 | 13808.47 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Asset | 50000 | 109.42 ms | 1.24 | 33 | 304.2 | 2188.4 | 14025.4 KB | 1.02 | +| ReadLine_ | .NET 8.0 | Asset | 50000 | 190.83 ms | 2.19 | 33 | 174.4 | 3816.6 | 122305.06 KB | 8.86 | +| CsvHelper | .NET 8.0 | Asset | 50000 | 185.03 ms | 2.09 | 33 | 179.9 | 3700.5 | 13972.06 KB | 1.01 | diff --git a/benchmarks/Neoverse.N1/Versions.txt b/benchmarks/Neoverse.N1/Versions.txt new file mode 100644 index 00000000..11d4ffb1 --- /dev/null +++ b/benchmarks/Neoverse.N1/Versions.txt @@ -0,0 +1 @@ +Sep 0.2.3, Sylvan 1.3.2.0, CsvHelper 30.0.1.0 \ No newline at end of file From b6fc05ec21c631a02ca24c6645079988ee215b5f Mon Sep 17 00:00:00 2001 From: ntr Date: Sat, 26 Aug 2023 15:17:11 +0200 Subject: [PATCH 26/30] work on auto benchmark README updates --- src/Sep.Test/ReadMeTest.cs | 137 +++++++++++++++++++++++++++++-------- 1 file changed, 107 insertions(+), 30 deletions(-) diff --git a/src/Sep.Test/ReadMeTest.cs b/src/Sep.Test/ReadMeTest.cs index e66a44cf..6a292de2 100644 --- a/src/Sep.Test/ReadMeTest.cs +++ b/src/Sep.Test/ReadMeTest.cs @@ -12,6 +12,10 @@ namespace nietras.SeparatedValues.Test; [TestClass] public class ReadMeTest { + static readonly string s_testSourceFilePath = SourceFile(); + static readonly string s_rootDirectory = Path.GetDirectoryName(s_testSourceFilePath) + @"../../../"; + static readonly string s_readmeFilePath = s_rootDirectory + @"README.md"; + [TestMethod] public void ReadMeTest_() { @@ -230,18 +234,72 @@ public void ReadMeTest_Example_CustomSep_DisableColCountCheck() foreach (var readRow in reader) { } } + //[TestMethod] + public void ReadMeTest_UpdateBenchmarksInMarkdown() + { + var readmeFilePath = s_readmeFilePath; + + // List benchmark file names and relevant parameters here + + + var benchmarksDirectory = Path.Combine(s_rootDirectory, "benchmarks"); + var processorDirectories = Directory.EnumerateDirectories(benchmarksDirectory).ToArray(); + var processors = processorDirectories.Select(LastDirectoryName).ToArray(); + + var processorDirectoryToBenchmarks = processorDirectories.ToDictionary(d => d, d => Directory.EnumerateFiles(d, "*.md")); + var grouped = processorDirectoryToBenchmarks.SelectMany(p => p.Value.Select(v => + (Processor: LastDirectoryName(p.Key), Benchmark: Path.GetFileName(v), Contents: File.ReadAllText(v), Versions: File.ReadAllText(Path.Combine(p.Key, "Versions.txt"))) + )) + .GroupBy(t => t.Benchmark); + + Trace.WriteLine(string.Join(", ", processorDirectories)); + Trace.WriteLine(string.Join(", ", processors)); + + var readmeLines = File.ReadAllLines(readmeFilePath); + + foreach (var g in grouped) + { + var fileName = g.Key; + var name = Path.GetFileNameWithoutExtension(fileName).Replace("Bench", " ").Trim().Replace(" ", " with "); + var readmeStartLine = $"##### {name}"; + var readmeEndLine = "##### "; + + var all = ""; + var results = g.ToArray(); + foreach (var result in results) + { + var section = $"###### {result.Processor} - {name} Benchmark Results ({result.Versions})"; + var benchmarkTable = GetBenchmarkTable(result.Contents); + var readmeContents = $"{section}{Environment.NewLine}{Environment.NewLine}{benchmarkTable}{Environment.NewLine}"; + all += readmeContents; + Trace.WriteLine(section); + } + + ReplaceReadmeLines(readmeLines, new[] { all }, readmeStartLine, "######", 0, readmeEndLine, -1); + } + + var newReadme = string.Join(Environment.NewLine, readmeLines) + Environment.NewLine; + File.WriteAllText(readmeFilePath, newReadme, Encoding.UTF8); + + static string LastDirectoryName(string d) => + d.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar).Last(); + + static string GetBenchmarkTable(string markdown) => + markdown.Substring(markdown.IndexOf('|')); + } + + [TestMethod] public void ReadMeTest_UpdateExampleCodeInMarkdown() { - var testSourceFile = SourceFile(); - - var rootDirectory = Path.GetDirectoryName(testSourceFile) + @"../../../"; + var testSourceFilePath = s_testSourceFilePath; + var readmeFilePath = s_readmeFilePath; + var rootDirectory = s_rootDirectory; - var readmeFile = rootDirectory + @"README.md"; - var readmeLines = File.ReadAllLines(readmeFile); + var readmeLines = File.ReadAllLines(readmeFilePath); // Update README examples - var testSourceLines = File.ReadAllLines(testSourceFile); + var testSourceLines = File.ReadAllLines(testSourceFilePath); var testBlocksToUpdate = new (string StartLineContains, string ReadmeLineBeforeCodeBlock)[] { (nameof(ReadMeTest_) + "()", "## Example"), @@ -253,7 +311,7 @@ public void ReadMeTest_UpdateExampleCodeInMarkdown() (nameof(ReadMeTest_Example_Copy_Rows) + "()", "### Example - Copy Rows"), }; readmeLines = UpdateReadme(testSourceLines, readmeLines, testBlocksToUpdate, - startLineOffset: 2, " }", endLineOffset: 0, whitespaceToRemove: 8); + sourceStartLineOffset: 2, " }", sourceEndLineOffset: 0, sourceWhitespaceToRemove: 8); var readerOptionsSourceLines = File.ReadAllLines(rootDirectory + @"src/Sep/SepReaderOptions.cs"); var readerOptionsBlocksToUpdate = new (string StartLineContains, string ReadmeLineBeforeCodeBlock)[] @@ -261,7 +319,7 @@ public void ReadMeTest_UpdateExampleCodeInMarkdown() ("/// ", "#### SepReaderOptions"), }; readmeLines = UpdateReadme(readerOptionsSourceLines, readmeLines, readerOptionsBlocksToUpdate, - startLineOffset: 0, "}", endLineOffset: 0, whitespaceToRemove: 4); + sourceStartLineOffset: 0, "}", sourceEndLineOffset: 0, sourceWhitespaceToRemove: 4); var writerOptionsSourceLines = File.ReadAllLines(rootDirectory + @"src/Sep/SepWriterOptions.cs"); var writerOptionsBlocksToUpdate = new (string StartLineContains, string ReadmeLineBeforeCodeBlock)[] @@ -269,41 +327,60 @@ public void ReadMeTest_UpdateExampleCodeInMarkdown() ("/// ", "#### SepWriterOptions"), }; readmeLines = UpdateReadme(writerOptionsSourceLines, readmeLines, writerOptionsBlocksToUpdate, - startLineOffset: 0, "}", endLineOffset: 0, whitespaceToRemove: 4); + sourceStartLineOffset: 0, "}", sourceEndLineOffset: 0, sourceWhitespaceToRemove: 4); var newReadme = string.Join(Environment.NewLine, readmeLines) + Environment.NewLine; - File.WriteAllText(readmeFile, newReadme, Encoding.UTF8); + File.WriteAllText(readmeFilePath, newReadme, Encoding.UTF8); } static string[] UpdateReadme(string[] sourceLines, string[] readmeLines, - (string StartLineContains, string ReadmeLineBeforeCodeBlock)[] blocksToUpdate, - int startLineOffset, string endLineStartsWith, int endLineOffset, int whitespaceToRemove) + (string StartLineContains, string ReadmeLineBefore)[] blocksToUpdate, + int sourceStartLineOffset, string sourceEndLineStartsWith, int sourceEndLineOffset, int sourceWhitespaceToRemove, + string readmeStartLineStartsWith = "```csharp", int readmeStartLineOffset = 1, + string readmeEndLineStartsWith = "```", int readmeEndLineOffset = 0) { - foreach (var (startLineContains, readmeLineBeforeCodeBlock) in blocksToUpdate) + foreach (var (startLineContains, readmeLineBeforeBlock) in blocksToUpdate) { var sourceExampleLines = SnipLines(sourceLines, - startLineContains, startLineOffset, - endLineStartsWith, endLineOffset, - whitespaceToRemove); - - var readmeLineBefore = Array.FindIndex(readmeLines, - l => l.StartsWith(readmeLineBeforeCodeBlock, StringComparison.Ordinal)) + 1; - if (readmeLineBefore == 0) - { throw new ArgumentException($"README line '{readmeLineBeforeCodeBlock}' not found."); } - - var readmeCodeStart = Array.FindIndex(readmeLines, readmeLineBefore, - l => l.StartsWith("```csharp", StringComparison.Ordinal)) + 1; - var readmeCodeEnd = Array.FindIndex(readmeLines, readmeCodeStart, - l => l.StartsWith("```", StringComparison.Ordinal)); - - readmeLines = readmeLines[..readmeCodeStart].AsEnumerable() - .Concat(sourceExampleLines) - .Concat(readmeLines[readmeCodeEnd..]).ToArray(); + startLineContains, sourceStartLineOffset, + sourceEndLineStartsWith, sourceEndLineOffset, + sourceWhitespaceToRemove); + + readmeLines = ReplaceReadmeLines(readmeLines, sourceExampleLines, readmeLineBeforeBlock, + readmeStartLineStartsWith, readmeStartLineOffset, readmeEndLineStartsWith, readmeEndLineOffset); } return readmeLines; } + static string[] ReplaceReadmeLines(string[] readmeLines, string[] newReadmeLines, string readmeLineBeforeBlock, + string readmeStartLineStartsWith, int readmeStartLineOffset, + string readmeEndLineStartsWith, int readmeEndLineOffset) + { + var readmeLineBeforeIndex = Array.FindIndex(readmeLines, + l => l.StartsWith(readmeLineBeforeBlock, StringComparison.Ordinal)) + 1; + if (readmeLineBeforeIndex == 0) + { throw new ArgumentException($"README line '{readmeLineBeforeBlock}' not found."); } + + return ReplaceReadmeLines(readmeLines, newReadmeLines, + readmeLineBeforeIndex, readmeStartLineStartsWith, readmeStartLineOffset, readmeEndLineStartsWith, readmeEndLineOffset); + } + + static string[] ReplaceReadmeLines(string[] readmeLines, string[] newReadmeLines, int readmeLineBeforeIndex, + string readmeStartLineStartsWith, int readmeStartLineOffset, + string readmeEndLineStartsWith, int readmeEndLineOffset) + { + var readmeReplaceStartIndex = Array.FindIndex(readmeLines, readmeLineBeforeIndex, + l => l.StartsWith(readmeStartLineStartsWith, StringComparison.Ordinal)) + readmeStartLineOffset; + var readmeReplaceEndIndex = Array.FindIndex(readmeLines, readmeReplaceStartIndex, + l => l.StartsWith(readmeEndLineStartsWith, StringComparison.Ordinal)) + readmeEndLineOffset; + + readmeLines = readmeLines[..readmeReplaceStartIndex].AsEnumerable() + .Concat(newReadmeLines) + .Concat(readmeLines[readmeReplaceEndIndex..]).ToArray(); + return readmeLines; + } + static string[] SnipLines(string[] sourceLines, string startLineContains, int startLineOffset, string endLineStartsWith, int endLineOffset, From e9c8f20dec06af99daf19165808bf811398918b7 Mon Sep 17 00:00:00 2001 From: ntr Date: Mon, 28 Aug 2023 14:30:22 +0200 Subject: [PATCH 27/30] update benchmarks with test run --- README.md | 389 ++++++++++++++++++++++++++----------- src/Sep.Test/ReadMeTest.cs | 38 ++-- 2 files changed, 297 insertions(+), 130 deletions(-) diff --git a/README.md b/README.md index 6a9f3978..b0788f04 100644 --- a/README.md +++ b/README.md @@ -729,43 +729,99 @@ optimized hashing of `ReadOnlySpan`, and thus not really due the the csv-parsing itself, since that is not a big part of the time consumed. At least not for a decently fast csv-parser. -###### `AMD 5950X` - PackageAssets Benchmark Results (Sep 0.2.1, Sylvan 1.3.2, CsvHelper 30.0.1) - -| Method | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | -|---------- |------ |------ |-----------:|------:|---:|--------:|-------:|-------------:|------------:| -| Sep______ | Row | 50000 | 2.624 ms | 1.00 | 29 | 11120.2 | 52.5 | 1.23 KB | 1.00 | -| Sylvan___ | Row | 50000 | 3.331 ms | 1.27 | 29 | 8760.6 | 66.6 | 7.23 KB | 5.89 | -| ReadLine_ | Row | 50000 | 13.397 ms | 5.05 | 29 | 2178.2 | 267.9 | 88608.27 KB | 72,183.66 | -| CsvHelper | Row | 50000 | 53.460 ms | 20.37 | 29 | 545.9 | 1069.2 | 21.09 KB | 17.18 | -| | | | | | | | | | | -| Sep______ | Cols | 50000 | 3.161 ms | 1.00 | 29 | 9231.8 | 63.2 | 1.14 KB | 1.00 | -| Sylvan___ | Cols | 50000 | 5.644 ms | 1.78 | 29 | 5169.9 | 112.9 | 7.23 KB | 6.35 | -| ReadLine_ | Cols | 50000 | 14.093 ms | 4.43 | 29 | 2070.7 | 281.9 | 88608.27 KB | 77,817.21 | -| CsvHelper | Cols | 50000 | 77.814 ms | 24.55 | 29 | 375.0 | 1556.3 | 446.74 KB | 392.34 | -| | | | | | | | | | | -| Sep______ | Asset | 50000 | 30.422 ms | 1.00 | 29 | 959.2 | 608.4 | 13799.67 KB | 1.00 | -| Sylvan___ | Asset | 50000 | 33.743 ms | 1.11 | 29 | 864.8 | 674.9 | 14025.32 KB | 1.02 | -| ReadLine_ | Asset | 50000 | 107.547 ms | 3.51 | 29 | 271.3 | 2150.9 | 102133.51 KB | 7.40 | -| CsvHelper | Asset | 50000 | 94.891 ms | 3.15 | 29 | 307.5 | 1897.8 | 13971.09 KB | 1.01 | - -###### `Neoverse N1` - PackageAssets Benchmark Results (Sep 0.2.1, Sylvan 1.3.2, CsvHelper 30.0.1) - -| Method | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | -|---------- |------ |------ |----------:|------:|---:|-------:|-------:|-------------:|------------:| -| Sep______ | Row | 50000 | 11.94 ms | 1.00 | 29 | 2436.4 | 238.8 | 1.13 KB | 1.00 | -| Sylvan___ | Row | 50000 | 34.06 ms | 2.86 | 29 | 853.9 | 681.2 | 6.25 KB | 5.53 | -| ReadLine_ | Row | 50000 | 41.34 ms | 3.46 | 29 | 703.6 | 826.7 | 88608.43 KB | 78,422.67 | -| CsvHelper | Row | 50000 | 109.04 ms | 9.13 | 29 | 266.8 | 2180.8 | 21 KB | 18.59 | -| | | | | | | | | | | -| Sep______ | Cols | 50000 | 14.87 ms | 1.00 | 29 | 1956.5 | 297.3 | 1.39 KB | 1.00 | -| Sylvan___ | Cols | 50000 | 40.24 ms | 2.71 | 29 | 722.8 | 804.8 | 6.25 KB | 4.50 | -| ReadLine_ | Cols | 50000 | 43.53 ms | 2.93 | 29 | 668.2 | 870.6 | 88608.43 KB | 63,808.04 | -| CsvHelper | Cols | 50000 | 157.57 ms | 10.60 | 29 | 184.6 | 3151.5 | 447.07 KB | 321.94 | -| | | | | | | | | | | -| Sep______ | Asset | 50000 | 69.29 ms | 1.00 | 29 | 419.8 | 1385.7 | 13800.13 KB | 1.00 | -| Sylvan___ | Asset | 50000 | 103.63 ms | 1.49 | 29 | 280.7 | 2072.6 | 14024.48 KB | 1.02 | -| ReadLine_ | Asset | 50000 | 159.70 ms | 2.31 | 29 | 182.1 | 3193.9 | 102134.85 KB | 7.40 | -| CsvHelper | Asset | 50000 | 185.31 ms | 2.67 | 29 | 157.0 | 3706.1 | 13971.42 KB | 1.01 | +###### AMD.Ryzen.9.5950X - PackageAssets Benchmark Results (Sep 0.2.3, Sylvan 1.3.2.0, CsvHelper 30.0.1.0) + +| Method | Runtime | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | +|---------- |--------- |------ |------ |-----------:|------:|---:|--------:|-------:|-------------:|------------:| +| Sep______ | .NET 7.0 | Row | 50000 | 2.565 ms | 1.00 | 29 | 11375.3 | 51.3 | 1.13 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Row | 50000 | 3.301 ms | 1.29 | 29 | 8840.1 | 66.0 | 7.17 KB | 6.34 | +| ReadLine_ | .NET 7.0 | Row | 50000 | 13.676 ms | 5.26 | 29 | 2133.7 | 273.5 | 88608.25 KB | 78,287.18 | +| CsvHelper | .NET 7.0 | Row | 50000 | 63.120 ms | 24.57 | 29 | 462.3 | 1262.4 | 20.65 KB | 18.25 | +| Sep______ | .NET 8.0 | Row | 50000 | 2.458 ms | 0.96 | 29 | 11872.7 | 49.2 | 1.13 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Row | 50000 | 3.053 ms | 1.19 | 29 | 9558.2 | 61.1 | 7.17 KB | 6.33 | +| ReadLine_ | .NET 8.0 | Row | 50000 | 12.642 ms | 4.96 | 29 | 2308.3 | 252.8 | 88608.24 KB | 78,287.18 | +| CsvHelper | .NET 8.0 | Row | 50000 | 44.515 ms | 17.37 | 29 | 655.5 | 890.3 | 20.59 KB | 18.19 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Cols | 50000 | 3.328 ms | 1.00 | 29 | 8769.4 | 66.6 | 1.13 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Cols | 50000 | 5.773 ms | 1.74 | 29 | 5054.4 | 115.5 | 7.18 KB | 6.33 | +| ReadLine_ | .NET 7.0 | Cols | 50000 | 13.962 ms | 4.11 | 29 | 2090.0 | 279.2 | 88608.25 KB | 78,152.32 | +| CsvHelper | .NET 7.0 | Cols | 50000 | 79.138 ms | 23.81 | 29 | 368.7 | 1582.8 | 446.31 KB | 393.65 | +| Sep______ | .NET 8.0 | Cols | 50000 | 3.188 ms | 0.96 | 29 | 9153.5 | 63.8 | 1.13 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Cols | 50000 | 5.598 ms | 1.68 | 29 | 5213.0 | 112.0 | 7.17 KB | 6.33 | +| ReadLine_ | .NET 8.0 | Cols | 50000 | 12.944 ms | 3.86 | 29 | 2254.4 | 258.9 | 88608.24 KB | 78,152.32 | +| CsvHelper | .NET 8.0 | Cols | 50000 | 71.520 ms | 21.27 | 29 | 408.0 | 1430.4 | 446.29 KB | 393.62 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Asset | 50000 | 30.729 ms | 1.00 | 29 | 949.6 | 614.6 | 13799.67 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Asset | 50000 | 42.129 ms | 1.37 | 29 | 692.7 | 842.6 | 14025.03 KB | 1.02 | +| ReadLine_ | .NET 7.0 | Asset | 50000 | 115.299 ms | 3.75 | 29 | 253.1 | 2306.0 | 102133.39 KB | 7.40 | +| CsvHelper | .NET 7.0 | Asset | 50000 | 104.802 ms | 3.41 | 29 | 278.4 | 2096.0 | 13972.08 KB | 1.01 | +| Sep______ | .NET 8.0 | Asset | 50000 | 30.395 ms | 0.99 | 29 | 960.1 | 607.9 | 13799.62 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Asset | 50000 | 38.198 ms | 1.24 | 29 | 764.0 | 764.0 | 14026.64 KB | 1.02 | +| ReadLine_ | .NET 8.0 | Asset | 50000 | 109.821 ms | 3.53 | 29 | 265.7 | 2196.4 | 102133.38 KB | 7.40 | +| CsvHelper | .NET 8.0 | Asset | 50000 | 85.305 ms | 2.78 | 29 | 342.1 | 1706.1 | 13972.36 KB | 1.01 | + +###### Intel.Xeon.Silver.4316.2.30GHz - PackageAssets Benchmark Results (Sep 0.2.3, Sylvan 1.3.2.0, CsvHelper 30.0.1.0) + +| Method | Runtime | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | +|---------- |--------- |------ |------ |-----------:|------:|---:|-------:|-------:|-------------:|------------:| +| Sep______ | .NET 7.0 | Row | 50000 | 5.948 ms | 1.00 | 29 | 4905.8 | 119.0 | 1.14 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Row | 50000 | 6.733 ms | 1.13 | 29 | 4334.0 | 134.7 | 7.18 KB | 6.29 | +| ReadLine_ | .NET 7.0 | Row | 50000 | 27.988 ms | 4.70 | 29 | 1042.6 | 559.8 | 88608.29 KB | 77,617.53 | +| CsvHelper | .NET 7.0 | Row | 50000 | 114.902 ms | 19.31 | 29 | 254.0 | 2298.0 | 20.65 KB | 18.09 | +| Sep______ | .NET 8.0 | Row | 50000 | 5.440 ms | 0.91 | 29 | 5363.8 | 108.8 | 1.29 KB | 1.13 | +| Sylvan___ | .NET 8.0 | Row | 50000 | 6.383 ms | 1.07 | 29 | 4571.5 | 127.7 | 7.18 KB | 6.29 | +| ReadLine_ | .NET 8.0 | Row | 50000 | 26.933 ms | 4.53 | 29 | 1083.5 | 538.7 | 88608.26 KB | 77,617.50 | +| CsvHelper | .NET 8.0 | Row | 50000 | 90.332 ms | 15.18 | 29 | 323.0 | 1806.6 | 20.69 KB | 18.12 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Cols | 50000 | 7.401 ms | 1.00 | 29 | 3942.7 | 148.0 | 1.15 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Cols | 50000 | 11.545 ms | 1.56 | 29 | 2527.5 | 230.9 | 7.19 KB | 6.28 | +| ReadLine_ | .NET 7.0 | Cols | 50000 | 28.892 ms | 3.90 | 29 | 1010.0 | 577.8 | 88608.29 KB | 77,352.84 | +| CsvHelper | .NET 7.0 | Cols | 50000 | 157.705 ms | 21.31 | 29 | 185.0 | 3154.1 | 446.5 KB | 389.78 | +| Sep______ | .NET 8.0 | Cols | 50000 | 6.683 ms | 0.90 | 29 | 4366.8 | 133.7 | 1.3 KB | 1.13 | +| Sylvan___ | .NET 8.0 | Cols | 50000 | 10.417 ms | 1.41 | 29 | 2801.2 | 208.3 | 7.19 KB | 6.28 | +| ReadLine_ | .NET 8.0 | Cols | 50000 | 27.292 ms | 3.69 | 29 | 1069.2 | 545.8 | 88608.26 KB | 77,352.82 | +| CsvHelper | .NET 8.0 | Cols | 50000 | 141.559 ms | 19.11 | 29 | 206.1 | 2831.2 | 446.45 KB | 389.74 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Asset | 50000 | 58.708 ms | 1.00 | 29 | 497.1 | 1174.2 | 13799.65 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Asset | 50000 | 76.436 ms | 1.31 | 29 | 381.8 | 1528.7 | 14025.71 KB | 1.02 | +| ReadLine_ | .NET 7.0 | Asset | 50000 | 174.574 ms | 3.00 | 29 | 167.2 | 3491.5 | 102133.35 KB | 7.40 | +| CsvHelper | .NET 7.0 | Asset | 50000 | 172.747 ms | 2.95 | 29 | 168.9 | 3454.9 | 13970.85 KB | 1.01 | +| Sep______ | .NET 8.0 | Asset | 50000 | 55.672 ms | 0.95 | 29 | 524.2 | 1113.4 | 13800.53 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Asset | 50000 | 71.428 ms | 1.22 | 29 | 408.5 | 1428.6 | 14026.38 KB | 1.02 | +| ReadLine_ | .NET 8.0 | Asset | 50000 | 162.203 ms | 2.76 | 29 | 179.9 | 3244.1 | 102133.69 KB | 7.40 | +| CsvHelper | .NET 8.0 | Asset | 50000 | 161.805 ms | 2.76 | 29 | 180.3 | 3236.1 | 13970.8 KB | 1.01 | + +###### Neoverse.N1 - PackageAssets Benchmark Results (Sep 0.2.3, Sylvan 1.3.2.0, CsvHelper 30.0.1.0) + +| Method | Runtime | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | +|---------- |--------- |------ |------ |----------:|------:|---:|-------:|-------:|-------------:|------------:| +| Sep______ | .NET 7.0 | Row | 50000 | 12.15 ms | 1.00 | 29 | 2393.9 | 243.0 | 1.11 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Row | 50000 | 34.31 ms | 2.82 | 29 | 847.7 | 686.2 | 6.25 KB | 5.64 | +| ReadLine_ | .NET 7.0 | Row | 50000 | 40.99 ms | 3.37 | 29 | 709.6 | 819.8 | 88608.34 KB | 79,942.68 | +| CsvHelper | .NET 7.0 | Row | 50000 | 107.97 ms | 8.89 | 29 | 269.4 | 2159.4 | 20.74 KB | 18.71 | +| Sep______ | .NET 8.0 | Row | 50000 | 12.01 ms | 0.99 | 29 | 2421.2 | 240.3 | 1.1 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Row | 50000 | 30.14 ms | 2.48 | 29 | 965.0 | 602.8 | 6.09 KB | 5.50 | +| ReadLine_ | .NET 8.0 | Row | 50000 | 39.05 ms | 3.21 | 29 | 744.9 | 780.9 | 88608.41 KB | 79,942.74 | +| CsvHelper | .NET 8.0 | Row | 50000 | 91.57 ms | 7.54 | 29 | 317.6 | 1831.5 | 20.77 KB | 18.74 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Cols | 50000 | 14.52 ms | 1.00 | 29 | 2002.8 | 290.5 | 1.12 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Cols | 50000 | 40.36 ms | 2.78 | 29 | 720.6 | 807.2 | 6.25 KB | 5.57 | +| ReadLine_ | .NET 7.0 | Cols | 50000 | 41.92 ms | 2.89 | 29 | 693.8 | 838.5 | 88608.36 KB | 78,899.97 | +| CsvHelper | .NET 7.0 | Cols | 50000 | 156.03 ms | 10.74 | 29 | 186.4 | 3120.6 | 446.66 KB | 397.72 | +| Sep______ | .NET 8.0 | Cols | 50000 | 14.24 ms | 0.98 | 29 | 2042.8 | 284.8 | 1.11 KB | 0.99 | +| Sylvan___ | .NET 8.0 | Cols | 50000 | 35.23 ms | 2.43 | 29 | 825.6 | 704.6 | 6.11 KB | 5.44 | +| ReadLine_ | .NET 8.0 | Cols | 50000 | 37.10 ms | 2.55 | 29 | 784.0 | 742.0 | 88608.32 KB | 78,899.93 | +| CsvHelper | .NET 8.0 | Cols | 50000 | 138.20 ms | 9.52 | 29 | 210.5 | 2763.9 | 446.61 KB | 397.68 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Asset | 50000 | 70.16 ms | 1.00 | 29 | 414.5 | 1403.3 | 13800.75 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Asset | 50000 | 107.28 ms | 1.53 | 29 | 271.1 | 2145.6 | 14025.09 KB | 1.02 | +| ReadLine_ | .NET 7.0 | Asset | 50000 | 159.87 ms | 2.27 | 29 | 181.9 | 3197.4 | 102134.11 KB | 7.40 | +| CsvHelper | .NET 7.0 | Asset | 50000 | 189.44 ms | 2.69 | 29 | 153.5 | 3788.8 | 13973.66 KB | 1.01 | +| Sep______ | .NET 8.0 | Asset | 50000 | 67.72 ms | 0.96 | 29 | 429.5 | 1354.3 | 13800.73 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Asset | 50000 | 100.09 ms | 1.43 | 29 | 290.6 | 2001.8 | 14024.23 KB | 1.02 | +| ReadLine_ | .NET 8.0 | Asset | 50000 | 144.19 ms | 2.06 | 29 | 201.7 | 2883.8 | 102134.74 KB | 7.40 | +| CsvHelper | .NET 8.0 | Asset | 50000 | 170.81 ms | 2.43 | 29 | 170.3 | 3416.1 | 13971.32 KB | 1.01 | + ##### PackageAssets with Quotes Benchmark Results `NCsvPerf` does not examine performance in the face of quotes in the csv. This @@ -780,43 +836,98 @@ looking at the numbers. For each row of 25 columns, there are 24 separators Adding quotes around each of the 25 columns will add 50 characters or almost triple the total to 76. -###### `AMD 5950X` - PackageAssets with Quotes Benchmark Results (Sep 0.2.1, Sylvan 1.3.2, CsvHelper 30.0.1) - -| Method | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | -|---------- |------ |------ |-----------:|------:|---:|-------:|-------:|-------------:|------------:| -| Sep______ | Row | 50000 | 6.936 ms | 1.00 | 33 | 4812.3 | 138.7 | 1.15 KB | 1.00 | -| Sylvan___ | Row | 50000 | 20.873 ms | 3.01 | 33 | 1599.1 | 417.5 | 7.33 KB | 6.35 | -| ReadLine_ | Row | 50000 | 15.593 ms | 2.23 | 33 | 2140.5 | 311.9 | 108778.78 KB | 94,238.13 | -| CsvHelper | Row | 50000 | 61.351 ms | 8.85 | 33 | 544.0 | 1227.0 | 20.65 KB | 17.89 | -| | | | | | | | | | | -| Sep______ | Cols | 50000 | 7.753 ms | 1.00 | 33 | 4305.1 | 155.1 | 1.33 KB | 1.00 | -| Sylvan___ | Cols | 50000 | 23.848 ms | 2.99 | 33 | 1399.6 | 476.9 | 7.33 KB | 5.51 | -| ReadLine_ | Cols | 50000 | 16.048 ms | 2.03 | 33 | 2079.8 | 321.0 | 108778.78 KB | 81,783.75 | -| CsvHelper | Cols | 50000 | 96.011 ms | 12.01 | 33 | 347.6 | 1920.2 | 446.5 KB | 335.69 | -| | | | | | | | | | | -| Sep______ | Asset | 50000 | 38.192 ms | 1.00 | 33 | 873.9 | 763.8 | 13808.03 KB | 1.00 | -| Sylvan___ | Asset | 50000 | 63.024 ms | 1.66 | 33 | 529.6 | 1260.5 | 14026.72 KB | 1.02 | -| ReadLine_ | Asset | 50000 | 120.942 ms | 3.17 | 33 | 276.0 | 2418.8 | 122304.67 KB | 8.86 | -| CsvHelper | Asset | 50000 | 110.273 ms | 2.92 | 33 | 302.7 | 2205.5 | 13970.79 KB | 1.01 | - -###### `Neoverse N1` - PackageAssets with Quotes Benchmark Results (Sep 0.2.1, Sylvan 1.3.2, CsvHelper 30.0.1) - -| Method | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | -|---------- |------ |------ |----------:|------:|---:|-------:|-------:|-------------:|------------:| -| Sep______ | Row | 50000 | 25.17 ms | 1.00 | 33 | 1322.5 | 503.3 | 1.39 KB | 1.00 | -| Sylvan___ | Row | 50000 | 45.92 ms | 1.82 | 33 | 724.8 | 918.4 | 6.25 KB | 4.50 | -| ReadLine_ | Row | 50000 | 50.73 ms | 2.01 | 33 | 656.0 | 1014.7 | 108779.08 KB | 78,333.18 | -| CsvHelper | Row | 50000 | 121.14 ms | 4.81 | 33 | 274.7 | 2422.8 | 21 KB | 15.13 | -| | | | | | | | | | | -| Sep______ | Cols | 50000 | 27.98 ms | 1.00 | 33 | 1189.4 | 559.7 | 1.39 KB | 1.00 | -| Sylvan___ | Cols | 50000 | 53.35 ms | 1.91 | 33 | 623.8 | 1067.1 | 7.01 KB | 5.05 | -| ReadLine_ | Cols | 50000 | 51.20 ms | 1.83 | 33 | 650.0 | 1024.1 | 108778.93 KB | 78,333.07 | -| CsvHelper | Cols | 50000 | 178.67 ms | 6.38 | 33 | 186.3 | 3573.3 | 447.07 KB | 321.94 | -| | | | | | | | | | | -| Sep______ | Asset | 50000 | 84.66 ms | 1.00 | 33 | 393.1 | 1693.2 | 13810.64 KB | 1.00 | -| Sylvan___ | Asset | 50000 | 115.08 ms | 1.36 | 33 | 289.2 | 2301.6 | 14024.41 KB | 1.02 | -| ReadLine_ | Asset | 50000 | 189.87 ms | 2.24 | 33 | 175.3 | 3797.4 | 122305.42 KB | 8.86 | -| CsvHelper | Asset | 50000 | 207.91 ms | 2.45 | 33 | 160.1 | 4158.3 | 13971.42 KB | 1.01 | +###### AMD.Ryzen.9.5950X - PackageAssets with Quotes Benchmark Results (Sep 0.2.3, Sylvan 1.3.2.0, CsvHelper 30.0.1.0) + +| Method | Runtime | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | +|---------- |--------- |------ |------ |-----------:|------:|---:|-------:|-------:|-------------:|------------:| +| Sep______ | .NET 7.0 | Row | 50000 | 7.414 ms | 1.00 | 33 | 4501.8 | 148.3 | 1.15 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Row | 50000 | 21.528 ms | 2.91 | 33 | 1550.4 | 430.6 | 7.33 KB | 6.40 | +| ReadLine_ | .NET 7.0 | Row | 50000 | 15.944 ms | 2.13 | 33 | 2093.4 | 318.9 | 108778.76 KB | 94,961.17 | +| CsvHelper | .NET 7.0 | Row | 50000 | 68.558 ms | 9.26 | 33 | 486.8 | 1371.2 | 20.65 KB | 18.03 | +| Sep______ | .NET 8.0 | Row | 50000 | 6.773 ms | 0.91 | 33 | 4928.3 | 135.5 | 1.14 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Row | 50000 | 18.409 ms | 2.47 | 33 | 1813.1 | 368.2 | 7.2 KB | 6.28 | +| ReadLine_ | .NET 8.0 | Row | 50000 | 14.955 ms | 2.03 | 33 | 2231.9 | 299.1 | 108778.75 KB | 94,961.16 | +| CsvHelper | .NET 8.0 | Row | 50000 | 53.158 ms | 7.17 | 33 | 627.9 | 1063.2 | 20.6 KB | 17.98 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Cols | 50000 | 7.723 ms | 1.00 | 33 | 4321.6 | 154.5 | 1.15 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Cols | 50000 | 23.941 ms | 3.10 | 33 | 1394.2 | 478.8 | 7.33 KB | 6.40 | +| ReadLine_ | .NET 7.0 | Cols | 50000 | 16.261 ms | 2.11 | 33 | 2052.6 | 325.2 | 108778.75 KB | 94,880.28 | +| CsvHelper | .NET 7.0 | Cols | 50000 | 90.538 ms | 11.65 | 33 | 368.7 | 1810.8 | 446.31 KB | 389.29 | +| Sep______ | .NET 8.0 | Cols | 50000 | 7.323 ms | 0.95 | 33 | 4557.6 | 146.5 | 1.14 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Cols | 50000 | 21.064 ms | 2.73 | 33 | 1584.6 | 421.3 | 7.31 KB | 6.38 | +| ReadLine_ | .NET 8.0 | Cols | 50000 | 15.523 ms | 2.02 | 33 | 2150.2 | 310.5 | 108778.75 KB | 94,880.27 | +| CsvHelper | .NET 8.0 | Cols | 50000 | 84.033 ms | 10.81 | 33 | 397.2 | 1680.7 | 446.35 KB | 389.32 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Asset | 50000 | 38.130 ms | 1.00 | 33 | 875.4 | 762.6 | 13808.03 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Asset | 50000 | 61.626 ms | 1.62 | 33 | 541.6 | 1232.5 | 14025.04 KB | 1.02 | +| ReadLine_ | .NET 7.0 | Asset | 50000 | 125.779 ms | 3.33 | 33 | 265.4 | 2515.6 | 122304.12 KB | 8.86 | +| CsvHelper | .NET 7.0 | Asset | 50000 | 114.214 ms | 3.00 | 33 | 292.2 | 2284.3 | 13971.43 KB | 1.01 | +| Sep______ | .NET 8.0 | Asset | 50000 | 34.585 ms | 0.91 | 33 | 965.1 | 691.7 | 13808.01 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Asset | 50000 | 53.850 ms | 1.41 | 33 | 619.8 | 1077.0 | 14025.15 KB | 1.02 | +| ReadLine_ | .NET 8.0 | Asset | 50000 | 115.295 ms | 3.02 | 33 | 289.5 | 2305.9 | 122304.01 KB | 8.86 | +| CsvHelper | .NET 8.0 | Asset | 50000 | 99.115 ms | 2.60 | 33 | 336.8 | 1982.3 | 13970.79 KB | 1.01 | + +###### Intel.Xeon.Silver.4316.2.30GHz - PackageAssets with Quotes Benchmark Results (Sep 0.2.3, Sylvan 1.3.2.0, CsvHelper 30.0.1.0) + +| Method | Runtime | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | +|---------- |--------- |------ |------ |----------:|------:|---:|-------:|-------:|-------------:|------------:| +| Sep______ | .NET 7.0 | Row | 50000 | 15.13 ms | 1.00 | 33 | 2206.5 | 302.5 | 1.17 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Row | 50000 | 42.25 ms | 2.80 | 33 | 790.0 | 845.0 | 7.26 KB | 6.22 | +| ReadLine_ | .NET 7.0 | Row | 50000 | 32.95 ms | 2.18 | 33 | 1013.0 | 659.0 | 108778.78 KB | 93,135.01 | +| CsvHelper | .NET 7.0 | Row | 50000 | 121.55 ms | 8.03 | 33 | 274.6 | 2431.1 | 20.84 KB | 17.84 | +| Sep______ | .NET 8.0 | Row | 50000 | 12.34 ms | 0.82 | 33 | 2705.0 | 246.8 | 1.31 KB | 1.12 | +| Sylvan___ | .NET 8.0 | Row | 50000 | 35.42 ms | 2.34 | 33 | 942.4 | 708.4 | 7.24 KB | 6.20 | +| ReadLine_ | .NET 8.0 | Row | 50000 | 32.15 ms | 2.13 | 33 | 1038.3 | 642.9 | 108778.77 KB | 93,135.00 | +| CsvHelper | .NET 8.0 | Row | 50000 | 104.02 ms | 6.88 | 33 | 320.9 | 2080.4 | 20.69 KB | 17.72 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Cols | 50000 | 15.80 ms | 1.00 | 33 | 2112.6 | 316.0 | 1.18 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Cols | 50000 | 45.83 ms | 2.91 | 33 | 728.3 | 916.6 | 7.33 KB | 6.24 | +| ReadLine_ | .NET 7.0 | Cols | 50000 | 33.98 ms | 2.15 | 33 | 982.2 | 679.7 | 108778.78 KB | 92,516.17 | +| CsvHelper | .NET 7.0 | Cols | 50000 | 177.61 ms | 11.23 | 33 | 187.9 | 3552.2 | 446.43 KB | 379.69 | +| Sep______ | .NET 8.0 | Cols | 50000 | 15.59 ms | 0.99 | 33 | 2140.6 | 311.8 | 1.5 KB | 1.28 | +| Sylvan___ | .NET 8.0 | Cols | 50000 | 38.85 ms | 2.46 | 33 | 859.2 | 777.0 | 7.25 KB | 6.16 | +| ReadLine_ | .NET 8.0 | Cols | 50000 | 32.64 ms | 2.06 | 33 | 1022.6 | 652.8 | 108778.77 KB | 92,516.16 | +| CsvHelper | .NET 8.0 | Cols | 50000 | 161.84 ms | 10.23 | 33 | 206.2 | 3236.9 | 446.45 KB | 379.70 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Asset | 50000 | 71.19 ms | 1.00 | 33 | 468.9 | 1423.8 | 13808.03 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Asset | 50000 | 106.82 ms | 1.50 | 33 | 312.5 | 2136.5 | 14025.33 KB | 1.02 | +| ReadLine_ | .NET 7.0 | Asset | 50000 | 205.79 ms | 2.89 | 33 | 162.2 | 4115.9 | 122304.11 KB | 8.86 | +| CsvHelper | .NET 7.0 | Asset | 50000 | 192.54 ms | 2.71 | 33 | 173.3 | 3850.9 | 13970.85 KB | 1.01 | +| Sep______ | .NET 8.0 | Asset | 50000 | 52.18 ms | 0.74 | 33 | 639.6 | 1043.7 | 13808.73 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Asset | 50000 | 96.05 ms | 1.35 | 33 | 347.5 | 1921.0 | 14026.75 KB | 1.02 | +| ReadLine_ | .NET 8.0 | Asset | 50000 | 202.80 ms | 2.82 | 33 | 164.6 | 4056.0 | 122304.21 KB | 8.86 | +| CsvHelper | .NET 8.0 | Asset | 50000 | 179.61 ms | 2.52 | 33 | 185.8 | 3592.1 | 13970.8 KB | 1.01 | + +###### Neoverse.N1 - PackageAssets with Quotes Benchmark Results (Sep 0.2.3, Sylvan 1.3.2.0, CsvHelper 30.0.1.0) + +| Method | Runtime | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | +|---------- |--------- |------ |------ |----------:|------:|---:|-------:|-------:|-------------:|------------:| +| Sep______ | .NET 7.0 | Row | 50000 | 25.47 ms | 1.00 | 33 | 1306.5 | 509.5 | 1.39 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Row | 50000 | 46.21 ms | 1.81 | 33 | 720.2 | 924.2 | 6.25 KB | 4.50 | +| ReadLine_ | .NET 7.0 | Row | 50000 | 49.46 ms | 1.94 | 33 | 673.0 | 989.1 | 108778.86 KB | 78,333.02 | +| CsvHelper | .NET 7.0 | Row | 50000 | 121.28 ms | 4.76 | 33 | 274.4 | 2425.6 | 20.74 KB | 14.93 | +| Sep______ | .NET 8.0 | Row | 50000 | 23.43 ms | 0.92 | 33 | 1420.5 | 468.6 | 1.36 KB | 0.98 | +| Sylvan___ | .NET 8.0 | Row | 50000 | 39.42 ms | 1.55 | 33 | 844.2 | 788.5 | 6.11 KB | 4.40 | +| ReadLine_ | .NET 8.0 | Row | 50000 | 47.68 ms | 1.87 | 33 | 698.1 | 953.5 | 108778.91 KB | 78,333.05 | +| CsvHelper | .NET 8.0 | Row | 50000 | 107.00 ms | 4.20 | 33 | 311.0 | 2140.1 | 20.77 KB | 14.96 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Cols | 50000 | 28.30 ms | 1.00 | 33 | 1175.9 | 566.1 | 1.39 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Cols | 50000 | 53.39 ms | 1.89 | 33 | 623.4 | 1067.8 | 6.25 KB | 4.50 | +| ReadLine_ | .NET 7.0 | Cols | 50000 | 50.71 ms | 1.79 | 33 | 656.3 | 1014.2 | 108778.93 KB | 78,333.07 | +| CsvHelper | .NET 7.0 | Cols | 50000 | 180.08 ms | 6.36 | 33 | 184.8 | 3601.5 | 446.66 KB | 321.65 | +| Sep______ | .NET 8.0 | Cols | 50000 | 25.68 ms | 0.91 | 33 | 1295.8 | 513.7 | 1.36 KB | 0.98 | +| Sylvan___ | .NET 8.0 | Cols | 50000 | 45.33 ms | 1.61 | 33 | 734.2 | 906.6 | 6.15 KB | 4.43 | +| ReadLine_ | .NET 8.0 | Cols | 50000 | 44.96 ms | 1.59 | 33 | 740.3 | 899.2 | 108778.91 KB | 78,333.05 | +| CsvHelper | .NET 8.0 | Cols | 50000 | 153.04 ms | 5.41 | 33 | 217.5 | 3060.7 | 446.61 KB | 321.61 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Asset | 50000 | 88.20 ms | 1.00 | 33 | 377.4 | 1764.0 | 13808.62 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Asset | 50000 | 115.22 ms | 1.31 | 33 | 288.9 | 2304.4 | 14024.52 KB | 1.02 | +| ReadLine_ | .NET 7.0 | Asset | 50000 | 200.14 ms | 2.28 | 33 | 166.3 | 4002.9 | 122305.55 KB | 8.86 | +| CsvHelper | .NET 7.0 | Asset | 50000 | 208.19 ms | 2.35 | 33 | 159.9 | 4163.8 | 13971.42 KB | 1.01 | +| Sep______ | .NET 8.0 | Asset | 50000 | 84.89 ms | 0.96 | 33 | 392.1 | 1697.7 | 13808.47 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Asset | 50000 | 109.42 ms | 1.24 | 33 | 304.2 | 2188.4 | 14025.4 KB | 1.02 | +| ReadLine_ | .NET 8.0 | Asset | 50000 | 190.83 ms | 2.19 | 33 | 174.4 | 3816.6 | 122305.06 KB | 8.86 | +| CsvHelper | .NET 8.0 | Asset | 50000 | 185.03 ms | 2.09 | 33 | 179.9 | 3700.5 | 13972.06 KB | 1.01 | #### Floats Reader Comparison Benchmarks @@ -883,43 +994,99 @@ naive `ReadLine` approach. With Sep being **>3.8x faster than CsvHelper**. It is a testament to how good the .NET and the .NET GC is that the ReadLine is pretty good compared to CsvHelper regardless of allocating a lot of strings. -##### `AMD 5950X` - Floats Benchmark Results (Sep 0.2.1, Sylvan 1.3.2, CsvHelper 30.0.1) - -| Method | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | -|---------- |------- |------ |-----------:|------:|---:|--------:|-------:|------------:|------------:| -| Sep______ | Row | 25000 | 2.655 ms | 1.00 | 27 | 10270.5 | 106.2 | 1.63 KB | 1.00 | -| Sylvan___ | Row | 25000 | 3.141 ms | 1.17 | 27 | 8680.9 | 125.6 | 10.61 KB | 6.51 | -| ReadLine_ | Row | 25000 | 13.953 ms | 5.24 | 27 | 1954.0 | 558.1 | 89986.87 KB | 55,243.74 | -| CsvHelper | Row | 25000 | 49.216 ms | 18.71 | 27 | 554.0 | 1968.7 | 20.74 KB | 12.73 | -| | | | | | | | | | | -| Sep______ | Cols | 25000 | 3.054 ms | 1.00 | 27 | 8927.5 | 122.2 | 1.63 KB | 1.00 | -| Sylvan___ | Cols | 25000 | 4.956 ms | 1.62 | 27 | 5500.8 | 198.3 | 10.56 KB | 6.49 | -| ReadLine_ | Cols | 25000 | 13.977 ms | 4.55 | 27 | 1950.6 | 559.1 | 89986.87 KB | 55,243.74 | -| CsvHelper | Cols | 25000 | 52.276 ms | 17.14 | 27 | 521.5 | 2091.0 | 28451.27 KB | 17,466.49 | -| | | | | | | | | | | -| Sep______ | Floats | 25000 | 33.263 ms | 1.00 | 27 | 819.6 | 1330.5 | 9.1 KB | 1.00 | -| Sylvan___ | Floats | 25000 | 72.137 ms | 2.17 | 27 | 377.9 | 2885.5 | 19.11 KB | 2.10 | -| ReadLine_ | Floats | 25000 | 83.109 ms | 2.50 | 27 | 328.0 | 3324.3 | 89993.63 KB | 9,894.08 | -| CsvHelper | Floats | 25000 | 128.119 ms | 3.86 | 27 | 212.8 | 5124.7 | 22039.48 KB | 2,423.07 | - -##### `Neoverse N1` - Floats Benchmark Results (Sep 0.2.1, Sylvan 1.3.2, CsvHelper 30.0.1) - -| Method | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | -|---------- |------- |------ |----------:|------:|---:|-------:|--------:|------------:|------------:| -| Sep______ | Row | 25000 | 11.46 ms | 1.00 | 27 | 2374.1 | 458.5 | 1.89 KB | 1.00 | -| Sylvan___ | Row | 25000 | 36.77 ms | 3.21 | 27 | 740.2 | 1470.8 | 10.48 KB | 5.54 | -| ReadLine_ | Row | 25000 | 42.43 ms | 3.70 | 27 | 641.4 | 1697.2 | 89987.08 KB | 47,547.36 | -| CsvHelper | Row | 25000 | 84.49 ms | 7.37 | 27 | 322.1 | 3379.7 | 21.74 KB | 11.49 | -| | | | | | | | | | | -| Sep______ | Cols | 25000 | 14.36 ms | 1.00 | 27 | 1895.9 | 574.2 | 1.89 KB | 1.00 | -| Sylvan___ | Cols | 25000 | 42.33 ms | 2.95 | 27 | 642.9 | 1693.4 | 11.48 KB | 6.07 | -| ReadLine_ | Cols | 25000 | 44.04 ms | 3.08 | 27 | 618.0 | 1761.4 | 89987.08 KB | 47,547.36 | -| CsvHelper | Cols | 25000 | 90.92 ms | 6.33 | 27 | 299.3 | 3636.8 | 28457.72 KB | 15,036.49 | -| | | | | | | | | | | -| Sep______ | Floats | 25000 | 64.87 ms | 1.00 | 27 | 419.5 | 2594.9 | 9.12 KB | 1.00 | -| Sylvan___ | Floats | 25000 | 210.41 ms | 3.24 | 27 | 129.3 | 8416.3 | 19.55 KB | 2.15 | -| ReadLine_ | Floats | 25000 | 217.31 ms | 3.35 | 27 | 125.2 | 8692.5 | 89994.37 KB | 9,872.96 | -| CsvHelper | Floats | 25000 | 296.95 ms | 4.58 | 27 | 91.7 | 11877.9 | 22040.05 KB | 2,417.94 | +##### AMD.Ryzen.9.5950X - FloatsReader Benchmark Results (Sep 0.2.3, Sylvan 1.3.2.0, CsvHelper 30.0.1.0) + +| Method | Runtime | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | +|---------- |--------- |------- |------ |-----------:|------:|---:|--------:|-------:|------------:|------------:| +| Sep______ | .NET 7.0 | Row | 25000 | 2.689 ms | 1.00 | 27 | 10137.6 | 107.6 | 1.56 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Row | 25000 | 3.017 ms | 1.12 | 27 | 9036.1 | 120.7 | 10.55 KB | 6.78 | +| ReadLine_ | .NET 7.0 | Row | 25000 | 13.916 ms | 5.14 | 27 | 1959.1 | 556.6 | 89986.83 KB | 57,808.36 | +| CsvHelper | .NET 7.0 | Row | 25000 | 49.716 ms | 18.60 | 27 | 548.4 | 1988.7 | 20.74 KB | 13.32 | +| Sep______ | .NET 8.0 | Row | 25000 | 2.610 ms | 0.97 | 27 | 10445.9 | 104.4 | 1.56 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Row | 25000 | 2.968 ms | 1.10 | 27 | 9185.7 | 118.7 | 10.55 KB | 6.78 | +| ReadLine_ | .NET 8.0 | Row | 25000 | 13.343 ms | 4.98 | 27 | 2043.3 | 533.7 | 89986.83 KB | 57,808.35 | +| CsvHelper | .NET 8.0 | Row | 25000 | 34.199 ms | 12.72 | 27 | 797.2 | 1368.0 | 20.61 KB | 13.24 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Cols | 25000 | 3.097 ms | 1.00 | 27 | 8804.5 | 123.9 | 1.56 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Cols | 25000 | 4.980 ms | 1.61 | 27 | 5474.5 | 199.2 | 10.56 KB | 6.77 | +| ReadLine_ | .NET 7.0 | Cols | 25000 | 13.959 ms | 4.51 | 27 | 1953.2 | 558.3 | 89986.84 KB | 57,735.92 | +| CsvHelper | .NET 7.0 | Cols | 25000 | 53.680 ms | 17.10 | 27 | 507.9 | 2147.2 | 28451.27 KB | 18,254.45 | +| Sep______ | .NET 8.0 | Cols | 25000 | 3.059 ms | 0.99 | 27 | 8912.6 | 122.4 | 1.56 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Cols | 25000 | 4.840 ms | 1.56 | 27 | 5632.9 | 193.6 | 10.55 KB | 6.77 | +| ReadLine_ | .NET 8.0 | Cols | 25000 | 13.615 ms | 4.40 | 27 | 2002.4 | 544.6 | 89986.83 KB | 57,735.91 | +| CsvHelper | .NET 8.0 | Cols | 25000 | 37.445 ms | 12.09 | 27 | 728.1 | 1497.8 | 28451.15 KB | 18,254.37 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Floats | 25000 | 33.069 ms | 1.00 | 27 | 824.4 | 1322.8 | 8.89 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Floats | 25000 | 71.582 ms | 2.16 | 27 | 380.9 | 2863.3 | 18.86 KB | 2.12 | +| ReadLine_ | .NET 7.0 | Floats | 25000 | 82.038 ms | 2.48 | 27 | 332.3 | 3281.5 | 89993.42 KB | 10,122.28 | +| CsvHelper | .NET 7.0 | Floats | 25000 | 127.852 ms | 3.86 | 27 | 213.2 | 5114.1 | 22039.48 KB | 2,478.96 | +| Sep______ | .NET 8.0 | Floats | 25000 | 22.521 ms | 0.68 | 27 | 1210.6 | 900.8 | 9.11 KB | 1.02 | +| Sylvan___ | .NET 8.0 | Floats | 25000 | 65.072 ms | 1.97 | 27 | 419.0 | 2602.9 | 18.84 KB | 2.12 | +| ReadLine_ | .NET 8.0 | Floats | 25000 | 72.803 ms | 2.20 | 27 | 374.5 | 2912.1 | 89990.3 KB | 10,121.93 | +| CsvHelper | .NET 8.0 | Floats | 25000 | 112.180 ms | 3.39 | 27 | 243.0 | 4487.2 | 22035.55 KB | 2,478.51 | + +##### Intel.Xeon.Silver.4316.2.30GHz - FloatsReader Benchmark Results (Sep 0.2.3, Sylvan 1.3.2.0, CsvHelper 30.0.1.0) + +| Method | Runtime | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | +|---------- |--------- |------- |------ |-----------:|------:|---:|-------:|--------:|------------:|------------:| +| Sep______ | .NET 7.0 | Row | 25000 | 5.417 ms | 1.00 | 27 | 5033.3 | 216.7 | 1.57 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Row | 25000 | 6.328 ms | 1.17 | 27 | 4308.3 | 253.1 | 10.56 KB | 6.74 | +| ReadLine_ | .NET 7.0 | Row | 25000 | 28.805 ms | 5.35 | 27 | 946.5 | 1152.2 | 89986.9 KB | 57,412.20 | +| CsvHelper | .NET 7.0 | Row | 25000 | 76.930 ms | 14.20 | 27 | 354.4 | 3077.2 | 20.74 KB | 13.23 | +| Sep______ | .NET 8.0 | Row | 25000 | 5.841 ms | 1.08 | 27 | 4667.7 | 233.6 | 1.72 KB | 1.10 | +| Sylvan___ | .NET 8.0 | Row | 25000 | 6.526 ms | 1.20 | 27 | 4177.8 | 261.0 | 10.56 KB | 6.74 | +| ReadLine_ | .NET 8.0 | Row | 25000 | 28.041 ms | 5.18 | 27 | 972.3 | 1121.7 | 89986.9 KB | 57,412.20 | +| CsvHelper | .NET 8.0 | Row | 25000 | 77.364 ms | 14.27 | 27 | 352.4 | 3094.5 | 20.77 KB | 13.25 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Cols | 25000 | 6.921 ms | 1.00 | 27 | 3939.4 | 276.8 | 1.57 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Cols | 25000 | 10.300 ms | 1.49 | 27 | 2647.0 | 412.0 | 10.58 KB | 6.72 | +| ReadLine_ | .NET 7.0 | Cols | 25000 | 29.077 ms | 4.19 | 27 | 937.6 | 1163.1 | 89986.9 KB | 57,198.38 | +| CsvHelper | .NET 7.0 | Cols | 25000 | 95.212 ms | 13.76 | 27 | 286.3 | 3808.5 | 28451.27 KB | 18,084.48 | +| Sep______ | .NET 8.0 | Cols | 25000 | 6.685 ms | 0.97 | 27 | 4078.0 | 267.4 | 1.73 KB | 1.10 | +| Sylvan___ | .NET 8.0 | Cols | 25000 | 9.724 ms | 1.41 | 27 | 2803.8 | 388.9 | 10.57 KB | 6.72 | +| ReadLine_ | .NET 8.0 | Cols | 25000 | 27.190 ms | 3.94 | 27 | 1002.7 | 1087.6 | 89986.89 KB | 57,198.37 | +| CsvHelper | .NET 8.0 | Cols | 25000 | 81.925 ms | 11.88 | 27 | 332.8 | 3277.0 | 28451.84 KB | 18,084.85 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Floats | 25000 | 61.789 ms | 1.00 | 27 | 441.2 | 2471.6 | 9.1 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Floats | 25000 | 146.737 ms | 2.37 | 27 | 185.8 | 5869.5 | 19.62 KB | 2.16 | +| ReadLine_ | .NET 7.0 | Floats | 25000 | 168.368 ms | 2.73 | 27 | 161.9 | 6734.7 | 89993.63 KB | 9,894.08 | +| CsvHelper | .NET 7.0 | Floats | 25000 | 264.441 ms | 4.28 | 27 | 103.1 | 10577.6 | 22039.48 KB | 2,423.07 | +| Sep______ | .NET 8.0 | Floats | 25000 | 44.122 ms | 0.71 | 27 | 617.9 | 1764.9 | 9.08 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Floats | 25000 | 135.504 ms | 2.19 | 27 | 201.2 | 5420.2 | 19.07 KB | 2.10 | +| ReadLine_ | .NET 8.0 | Floats | 25000 | 151.400 ms | 2.45 | 27 | 180.1 | 6056.0 | 89990.48 KB | 9,893.74 | +| CsvHelper | .NET 8.0 | Floats | 25000 | 231.426 ms | 3.75 | 27 | 117.8 | 9257.1 | 22036.58 KB | 2,422.75 | + +##### Neoverse.N1 - FloatsReader Benchmark Results (Sep 0.2.3, Sylvan 1.3.2.0, CsvHelper 30.0.1.0) + +| Method | Runtime | Scope | Rows | Mean | Ratio | MB | MB/s | ns/row | Allocated | Alloc Ratio | +|---------- |--------- |------- |------ |----------:|------:|---:|-------:|--------:|------------:|------------:| +| Sep______ | .NET 7.0 | Row | 25000 | 11.54 ms | 1.00 | 27 | 2359.4 | 461.4 | 1.54 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Row | 25000 | 37.00 ms | 3.21 | 27 | 735.6 | 1479.9 | 10.48 KB | 6.80 | +| ReadLine_ | .NET 7.0 | Row | 25000 | 40.34 ms | 3.50 | 27 | 674.7 | 1613.6 | 89986.96 KB | 58,394.58 | +| CsvHelper | .NET 7.0 | Row | 25000 | 84.31 ms | 7.31 | 27 | 322.8 | 3372.4 | 20.82 KB | 13.51 | +| Sep______ | .NET 8.0 | Row | 25000 | 11.63 ms | 1.01 | 27 | 2339.4 | 465.3 | 1.54 KB | 1.00 | +| Sylvan___ | .NET 8.0 | Row | 25000 | 38.26 ms | 3.32 | 27 | 711.3 | 1530.4 | 10.3 KB | 6.69 | +| ReadLine_ | .NET 8.0 | Row | 25000 | 40.77 ms | 3.53 | 27 | 667.5 | 1630.8 | 89987.06 KB | 58,394.64 | +| CsvHelper | .NET 8.0 | Row | 25000 | 79.69 ms | 6.91 | 27 | 341.5 | 3187.7 | 20.86 KB | 13.53 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Cols | 25000 | 13.37 ms | 1.00 | 27 | 2035.0 | 535.0 | 1.55 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Cols | 25000 | 41.82 ms | 3.13 | 27 | 650.8 | 1672.8 | 10.48 KB | 6.74 | +| ReadLine_ | .NET 7.0 | Cols | 25000 | 42.16 ms | 3.15 | 27 | 645.5 | 1686.4 | 89986.99 KB | 57,881.08 | +| CsvHelper | .NET 7.0 | Cols | 25000 | 90.73 ms | 6.79 | 27 | 300.0 | 3629.2 | 28451.35 KB | 18,300.37 | +| Sep______ | .NET 8.0 | Cols | 25000 | 13.74 ms | 1.03 | 27 | 1980.9 | 549.6 | 1.55 KB | 0.99 | +| Sylvan___ | .NET 8.0 | Cols | 25000 | 42.55 ms | 3.18 | 27 | 639.7 | 1701.9 | 10.33 KB | 6.64 | +| ReadLine_ | .NET 8.0 | Cols | 25000 | 38.88 ms | 2.90 | 27 | 700.0 | 1555.1 | 89987.06 KB | 57,881.12 | +| CsvHelper | .NET 8.0 | Cols | 25000 | 85.89 ms | 6.42 | 27 | 316.9 | 3435.7 | 28451.39 KB | 18,300.39 | +| | | | | | | | | | | | +| Sep______ | .NET 7.0 | Floats | 25000 | 64.82 ms | 1.00 | 27 | 419.9 | 2592.6 | 9.12 KB | 1.00 | +| Sylvan___ | .NET 7.0 | Floats | 25000 | 209.21 ms | 3.23 | 27 | 130.1 | 8368.4 | 19.55 KB | 2.15 | +| ReadLine_ | .NET 7.0 | Floats | 25000 | 214.76 ms | 3.31 | 27 | 126.7 | 8590.6 | 89994.37 KB | 9,872.96 | +| CsvHelper | .NET 7.0 | Floats | 25000 | 297.94 ms | 4.60 | 27 | 91.3 | 11917.5 | 22040.05 KB | 2,417.94 | +| Sep______ | .NET 8.0 | Floats | 25000 | 53.37 ms | 0.82 | 27 | 510.0 | 2134.7 | 8.95 KB | 0.98 | +| Sylvan___ | .NET 8.0 | Floats | 25000 | 164.95 ms | 2.55 | 27 | 165.0 | 6598.0 | 18.84 KB | 2.07 | +| ReadLine_ | .NET 8.0 | Floats | 25000 | 160.20 ms | 2.47 | 27 | 169.9 | 6408.1 | 89990.64 KB | 9,872.55 | +| CsvHelper | .NET 8.0 | Floats | 25000 | 231.15 ms | 3.57 | 27 | 117.7 | 9245.8 | 22037.14 KB | 2,417.62 | + ### Writer Comparison Benchmarks Writer benchmarks are still pending, but Sep is unlikely to be the fastest here diff --git a/src/Sep.Test/ReadMeTest.cs b/src/Sep.Test/ReadMeTest.cs index 6a292de2..84971b49 100644 --- a/src/Sep.Test/ReadMeTest.cs +++ b/src/Sep.Test/ReadMeTest.cs @@ -234,48 +234,48 @@ public void ReadMeTest_Example_CustomSep_DisableColCountCheck() foreach (var readRow in reader) { } } - //[TestMethod] + [TestMethod] public void ReadMeTest_UpdateBenchmarksInMarkdown() { var readmeFilePath = s_readmeFilePath; // List benchmark file names and relevant parameters here - + var benchmarkFileNameToConfig = new Dictionary() + { + { "PackageAssetsBench.md", new("##### PackageAssets Benchmark Results", "##### ", "###### ") }, + { "PackageAssetsBenchQuotes.md", new("##### PackageAssets with Quotes Benchmark Results", "#### ", "###### ") }, + { "FloatsReaderBench.md", new("#### Floats Reader Comparison Benchmarks", "### Writer", "##### ") }, + }; var benchmarksDirectory = Path.Combine(s_rootDirectory, "benchmarks"); var processorDirectories = Directory.EnumerateDirectories(benchmarksDirectory).ToArray(); var processors = processorDirectories.Select(LastDirectoryName).ToArray(); - var processorDirectoryToBenchmarks = processorDirectories.ToDictionary(d => d, d => Directory.EnumerateFiles(d, "*.md")); - var grouped = processorDirectoryToBenchmarks.SelectMany(p => p.Value.Select(v => - (Processor: LastDirectoryName(p.Key), Benchmark: Path.GetFileName(v), Contents: File.ReadAllText(v), Versions: File.ReadAllText(Path.Combine(p.Key, "Versions.txt"))) - )) - .GroupBy(t => t.Benchmark); - Trace.WriteLine(string.Join(", ", processorDirectories)); Trace.WriteLine(string.Join(", ", processors)); var readmeLines = File.ReadAllLines(readmeFilePath); - foreach (var g in grouped) + foreach (var (fileName, config) in benchmarkFileNameToConfig) { - var fileName = g.Key; var name = Path.GetFileNameWithoutExtension(fileName).Replace("Bench", " ").Trim().Replace(" ", " with "); - var readmeStartLine = $"##### {name}"; - var readmeEndLine = "##### "; - + var prefix = config.SectionPrefix; + var readmeBefore = config.ReadmeBefore; + var readmeEndLine = config.ReadmeEnd; var all = ""; - var results = g.ToArray(); - foreach (var result in results) + foreach (var processorDirectory in processorDirectories) { - var section = $"###### {result.Processor} - {name} Benchmark Results ({result.Versions})"; - var benchmarkTable = GetBenchmarkTable(result.Contents); + var versions = File.ReadAllText(Path.Combine(processorDirectory, "Versions.txt")); + var contents = File.ReadAllText(Path.Combine(processorDirectory, fileName)); + var processor = LastDirectoryName(processorDirectory); + + var section = $"{prefix}{processor} - {name} Benchmark Results ({versions})"; + var benchmarkTable = GetBenchmarkTable(contents); var readmeContents = $"{section}{Environment.NewLine}{Environment.NewLine}{benchmarkTable}{Environment.NewLine}"; all += readmeContents; Trace.WriteLine(section); } - - ReplaceReadmeLines(readmeLines, new[] { all }, readmeStartLine, "######", 0, readmeEndLine, -1); + readmeLines = ReplaceReadmeLines(readmeLines, new[] { all }, readmeBefore, prefix, 0, readmeEndLine, 0); } var newReadme = string.Join(Environment.NewLine, readmeLines) + Environment.NewLine; From d03a881a833ce285928b61676b7732cdf83958e3 Mon Sep 17 00:00:00 2001 From: ntr Date: Mon, 28 Aug 2023 14:31:22 +0200 Subject: [PATCH 28/30] cleanup --- src/Sep.Test/ReadMeTest.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Sep.Test/ReadMeTest.cs b/src/Sep.Test/ReadMeTest.cs index 84971b49..283c8707 100644 --- a/src/Sep.Test/ReadMeTest.cs +++ b/src/Sep.Test/ReadMeTest.cs @@ -239,7 +239,6 @@ public void ReadMeTest_UpdateBenchmarksInMarkdown() { var readmeFilePath = s_readmeFilePath; - // List benchmark file names and relevant parameters here var benchmarkFileNameToConfig = new Dictionary() { { "PackageAssetsBench.md", new("##### PackageAssets Benchmark Results", "##### ", "###### ") }, @@ -251,9 +250,6 @@ public void ReadMeTest_UpdateBenchmarksInMarkdown() var processorDirectories = Directory.EnumerateDirectories(benchmarksDirectory).ToArray(); var processors = processorDirectories.Select(LastDirectoryName).ToArray(); - Trace.WriteLine(string.Join(", ", processorDirectories)); - Trace.WriteLine(string.Join(", ", processors)); - var readmeLines = File.ReadAllLines(readmeFilePath); foreach (var (fileName, config) in benchmarkFileNameToConfig) @@ -288,7 +284,6 @@ static string GetBenchmarkTable(string markdown) => markdown.Substring(markdown.IndexOf('|')); } - [TestMethod] public void ReadMeTest_UpdateExampleCodeInMarkdown() { From 0f47cb984af00e58e68a12974a3b7e92de511efd Mon Sep 17 00:00:00 2001 From: ntr Date: Sun, 3 Sep 2023 15:44:47 +0200 Subject: [PATCH 29/30] update Runtime and Platforms --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b0788f04..03005a39 100644 --- a/README.md +++ b/README.md @@ -612,7 +612,8 @@ than that. Or how many *times* more bytes are allocated in `Alloc Ratio`. ### Runtime and Platforms The following runtime is used for benchmarking: -* `NET 7.0.5 (7.0.523.17405)` +* `NET 7.0.X` +* `NET 8.0.X` The following platforms are used for benchmarking: @@ -621,6 +622,11 @@ The following platforms are used for benchmarking: OS=Windows 10 (10.0.19044.2846/21H2/November2021Update) AMD Ryzen 9 5950X, 1 CPU, 32 logical and 16 physical cores ``` +* `Intel Xeon Silver 4316` X64 Platform Information + ``` ini + OS=Windows 10 (10.0.17763.3287/1809/October2018Update/Redstone5) + Intel Xeon Silver 4316 CPU 2.30GHz, 1 CPU, 40 logical and 20 physical cores + ``` * `Neoverse N1` ARM64 Platform Information (cloud instance) ```ini OS=ubuntu 22.04 From a44f8720ea565c3dc1c6cb3e1af7eaaf220cea01 Mon Sep 17 00:00:00 2001 From: ntr Date: Sun, 3 Sep 2023 16:03:50 +0200 Subject: [PATCH 30/30] nits --- src/Sep.ComparisonBenchmarks/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Sep.ComparisonBenchmarks/Program.cs b/src/Sep.ComparisonBenchmarks/Program.cs index e85e8c01..e26c28ee 100644 --- a/src/Sep.ComparisonBenchmarks/Program.cs +++ b/src/Sep.ComparisonBenchmarks/Program.cs @@ -31,7 +31,7 @@ await PackageAssetsTestData.EnsurePackageAssets().ConfigureAwait(true); // Use args as switch to run BDN or not e.g. BDN only run when using script -if (true || args.Length > 0) +if (args.Length > 0) { var baseConfig = ManualConfig.CreateEmpty() .AddColumnProvider(DefaultColumnProviders.Instance)