diff --git a/src/FastIDs.TypeId/FastIDs.TypeId.sln b/src/FastIDs.TypeId/FastIDs.TypeId.sln index fab2f69..6105183 100644 --- a/src/FastIDs.TypeId/FastIDs.TypeId.sln +++ b/src/FastIDs.TypeId/FastIDs.TypeId.sln @@ -6,6 +6,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TypeId.Tests", "TypeId.Test EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TypeId.Benchmarks", "TypeId.Benchmarks\TypeId.Benchmarks.csproj", "{6B112FAC-0310-448C-8654-BE41A7FC39CC}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TypeId.BenchmarksNuget", "TypeId.BenchmarksNuget\TypeId.BenchmarksNuget.csproj", "{43BB99E6-90DF-4A1E-B539-B2B3AB6F50DF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -24,5 +26,9 @@ Global {6B112FAC-0310-448C-8654-BE41A7FC39CC}.Debug|Any CPU.Build.0 = Debug|Any CPU {6B112FAC-0310-448C-8654-BE41A7FC39CC}.Release|Any CPU.ActiveCfg = Release|Any CPU {6B112FAC-0310-448C-8654-BE41A7FC39CC}.Release|Any CPU.Build.0 = Release|Any CPU + {43BB99E6-90DF-4A1E-B539-B2B3AB6F50DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {43BB99E6-90DF-4A1E-B539-B2B3AB6F50DF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {43BB99E6-90DF-4A1E-B539-B2B3AB6F50DF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {43BB99E6-90DF-4A1E-B539-B2B3AB6F50DF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/src/FastIDs.TypeId/TypeId.Benchmarks/InternalBenchmarks/IdAlphabetValidationBenchmarks.cs b/src/FastIDs.TypeId/TypeId.Benchmarks/InternalBenchmarks/IdAlphabetValidationBenchmarks.cs index ba4ac88..b27095e 100644 --- a/src/FastIDs.TypeId/TypeId.Benchmarks/InternalBenchmarks/IdAlphabetValidationBenchmarks.cs +++ b/src/FastIDs.TypeId/TypeId.Benchmarks/InternalBenchmarks/IdAlphabetValidationBenchmarks.cs @@ -99,6 +99,32 @@ public bool SearchValuesLoopInvalid() return isValid; } + [Benchmark] + [BenchmarkCategory("Valid")] + public bool SearchValuesFullValid() + { + var isValid = false; + foreach (var id in _validIds) + { + isValid &= !id.AsSpan().ContainsAnyExcept(_searchValues); + } + + return isValid; + } + + [Benchmark] + [BenchmarkCategory("Invalid")] + public bool SearchValuesFullInvalid() + { + var isValid = false; + foreach (var id in _invalidIds) + { + isValid &= !id.AsSpan().ContainsAnyExcept(_searchValues); + } + + return isValid; + } + [Benchmark] [BenchmarkCategory("Invalid")] public bool SearchValuesUnrollInvalid() diff --git a/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdComparison.cs b/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdComparison.cs index c62bd4e..4a0b035 100644 --- a/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdComparison.cs +++ b/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdComparison.cs @@ -10,17 +10,17 @@ namespace FastIDs.TypeId.Benchmarks.LibraryComparison; [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] public class TypeIdComparison { - [Params(0, 5, 10, 30, 63)] + [Params(0, 5, 15, 63)] public int PrefixLength; - private string _suffix = "01h455vb4pex5vsknk084sn02q"; - - private TypeId[] _fastIdTypeIds = Array.Empty(); - private TypeIdDecoded[] _fastIdTypeIdsDecoded = Array.Empty(); - private TcKs.TypeId.TypeId[] _tcKsTypeIds = Array.Empty(); - private global::TypeId.TypeId[] _cbuctokTypeIds = Array.Empty(); + private const string Suffix = "01h455vb4pex5vsknk084sn02q"; + + private TypeId[] _fastIdTypeIds = []; + private TypeIdDecoded[] _fastIdTypeIdsDecoded = []; + private TcKs.TypeId.TypeId[] _tcKsTypeIds = []; + private global::TypeId.TypeId[] _cbuctokTypeIds = []; #if NET10_0_OR_GREATER - private TypeSafeId.TypeId[] _typeSafeIds = Array.Empty>(); + private TypeSafeId.TypeId[] _typeSafeIds = []; #endif private readonly string _prefixFull; @@ -42,25 +42,27 @@ public void Setup() { var prefix = _prefixFull[..PrefixLength]; var typeIdStr = PrefixLength > 0 - ? $"{prefix}_{_suffix}" - : _suffix; + ? $"{prefix}_{Suffix}" + : Suffix; #if NET10_0_OR_GREATER +#pragma warning disable CS0618 // Type or member is obsolete TypeSafeId.TypeId.SetPrefix(prefix); +#pragma warning restore CS0618 // Type or member is obsolete #endif - _fastIdTypeIds = new[] { TypeId.Parse(typeIdStr), TypeId.Parse(typeIdStr) }; - _fastIdTypeIdsDecoded = new[] { TypeId.Parse(typeIdStr).Decode(), TypeId.Parse(typeIdStr).Decode() }; + _fastIdTypeIds = [TypeId.Parse(typeIdStr), TypeId.Parse(typeIdStr)]; + _fastIdTypeIdsDecoded = [TypeId.Parse(typeIdStr).Decode(), TypeId.Parse(typeIdStr).Decode()]; - _tcKsTypeIds = Array.Empty(); + _tcKsTypeIds = []; if (TcKs.TypeId.TypeId.TryParse(typeIdStr, out var parsed)) { - _tcKsTypeIds = new[] { parsed, parsed }; + _tcKsTypeIds = [parsed, parsed]; } - _cbuctokTypeIds = new[] { global::TypeId.TypeId.Parse(typeIdStr), global::TypeId.TypeId.Parse(typeIdStr) }; + _cbuctokTypeIds = [global::TypeId.TypeId.Parse(typeIdStr), global::TypeId.TypeId.Parse(typeIdStr)]; #if NET10_0_OR_GREATER - _typeSafeIds = new[] { TypeSafeId.TypeId.Parse(typeIdStr), TypeSafeId.TypeId.Parse(typeIdStr) }; + _typeSafeIds = [TypeSafeId.TypeId.Parse(typeIdStr), TypeSafeId.TypeId.Parse(typeIdStr)]; #endif } diff --git a/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdGeneration.cs b/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdGeneration.cs index 7a66192..8de0d5e 100644 --- a/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdGeneration.cs +++ b/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdGeneration.cs @@ -8,7 +8,7 @@ namespace FastIDs.TypeId.Benchmarks.LibraryComparison; [MarkdownExporterAttribute.Default] public class TypeIdGeneration { - [Params(0, 5, 10, 30, 63)] + [Params(0, 5, 15, 63)] public int PrefixLength; private string _prefix = ""; @@ -32,7 +32,9 @@ public void Setup() _prefix = _prefixFull[..PrefixLength]; #if NET10_0_OR_GREATER +#pragma warning disable CS0618 // Type or member is obsolete TypeSafeId.TypeId.SetPrefix(_prefix); +#pragma warning restore CS0618 // Type or member is obsolete #endif } diff --git a/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdParsing.cs b/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdParsing.cs index f80924d..86076ca 100644 --- a/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdParsing.cs +++ b/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdParsing.cs @@ -9,7 +9,7 @@ namespace FastIDs.TypeId.Benchmarks.LibraryComparison; [MarkdownExporterAttribute.GitHub] public class TypeIdParsing { - [Params(0, 5, 10, 30, 63)] + [Params(0, 5, 15, 63)] public int PrefixLength; private string _typeIdString = ""; @@ -37,7 +37,9 @@ public void Setup() _typeIdString = TypeId.FromUuidV7(prefix, _uuidV7).ToString(); #if NET10_0_OR_GREATER +#pragma warning disable CS0618 // Type or member is obsolete TypeSafeId.TypeId.SetPrefix(prefix); +#pragma warning restore CS0618 // Type or member is obsolete #endif } diff --git a/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdRetrieveFlow.cs b/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdRetrieveFlow.cs index adf17ee..4b2aaba 100644 --- a/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdRetrieveFlow.cs +++ b/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdRetrieveFlow.cs @@ -8,7 +8,7 @@ namespace FastIDs.TypeId.Benchmarks.LibraryComparison; [MarkdownExporterAttribute.Default] public class TypeIdRetrieveFlow { - [Params(0, 5, 10, 30, 63)] + [Params(0, 5, 15, 63)] public int PrefixLength; private string _typeIdString = ""; @@ -36,7 +36,9 @@ public void Setup() _typeIdString = TypeId.FromUuidV7(prefix, _uuidV7).ToString(); #if NET10_0_OR_GREATER +#pragma warning disable CS0618 // Type or member is obsolete TypeSafeId.TypeId.SetPrefix(prefix); +#pragma warning restore CS0618 // Type or member is obsolete #endif } diff --git a/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdString.cs b/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdString.cs index a3cf8b1..2b88666 100644 --- a/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdString.cs +++ b/src/FastIDs.TypeId/TypeId.Benchmarks/LibraryComparison/TypeIdString.cs @@ -8,7 +8,7 @@ namespace FastIDs.TypeId.Benchmarks.LibraryComparison; [MarkdownExporterAttribute.Default] public class TypeIdString { - [Params(0, 5, 10, 30, 63)] + [Params(0, 5, 15, 63)] public int PrefixLength; private readonly string _prefixFull; @@ -48,7 +48,9 @@ public void Setup() #if NET10_0_OR_GREATER _typeSafeIdTypeId = new TypeSafeId.TypeId(_uuidV7); +#pragma warning disable CS0618 // Type or member is obsolete global::TypeSafeId.TypeId.SetPrefix(prefix); +#pragma warning restore CS0618 // Type or member is obsolete #endif } diff --git a/src/FastIDs.TypeId/TypeId.Benchmarks/Program.cs b/src/FastIDs.TypeId/TypeId.Benchmarks/Program.cs index d835d0f..ef9683c 100644 --- a/src/FastIDs.TypeId/TypeId.Benchmarks/Program.cs +++ b/src/FastIDs.TypeId/TypeId.Benchmarks/Program.cs @@ -10,4 +10,4 @@ // .AddJob(Job.Default.WithId("Vector256").WithEnvironmentVariable("DOTNET_EnableAVX512F", "0")) // .AddJob(Job.Default.WithId("Vector512")); -BenchmarkSwitcher.FromAssembly(Assembly.GetExecutingAssembly()).Run(config: config); \ No newline at end of file +BenchmarkSwitcher.FromAssembly(Assembly.GetExecutingAssembly()).Run(config: config, args: args); \ No newline at end of file diff --git a/src/FastIDs.TypeId/TypeId.BenchmarksNuget/Program.cs b/src/FastIDs.TypeId/TypeId.BenchmarksNuget/Program.cs new file mode 100644 index 0000000..0a68549 --- /dev/null +++ b/src/FastIDs.TypeId/TypeId.BenchmarksNuget/Program.cs @@ -0,0 +1,28 @@ +using System.Reflection; +using BenchmarkDotNet.Columns; +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Environments; +using BenchmarkDotNet.Jobs; +using BenchmarkDotNet.Reports; +using BenchmarkDotNet.Running; + +var config = DefaultConfig.Instance + .WithOptions(ConfigOptions.JoinSummary) + .HideColumns("Arguments", "RatioSD", "Alloc Ratio") + .AddLogicalGroupRules(BenchmarkLogicalGroupRule.ByMethod); + +string[] typeIdNugetVersions = +[ + "1.3.0-alpha.0.1", + "1.2.1", + "1.1.0", + "1.0.0" +]; + +for (var i = 0; i < typeIdNugetVersions.Length; i++) +{ + var version = typeIdNugetVersions[i]; + config = config.AddJob(Job.Default.WithMsBuildArguments($"/p:SciVersion={version}").WithId(version).WithBaseline(i == 0)); +} + +BenchmarkSwitcher.FromAssembly(Assembly.GetExecutingAssembly()).Run(config: config, args: args); diff --git a/src/FastIDs.TypeId/TypeId.BenchmarksNuget/TypeId.BenchmarksNuget.csproj b/src/FastIDs.TypeId/TypeId.BenchmarksNuget/TypeId.BenchmarksNuget.csproj new file mode 100644 index 0000000..41e8696 --- /dev/null +++ b/src/FastIDs.TypeId/TypeId.BenchmarksNuget/TypeId.BenchmarksNuget.csproj @@ -0,0 +1,20 @@ + + + + Exe + net8.0;net10.0 + enable + enable + + + + + 1.0.0 + + + + + + + + diff --git a/src/FastIDs.TypeId/TypeId.BenchmarksNuget/TypeIdBasicOps.cs b/src/FastIDs.TypeId/TypeId.BenchmarksNuget/TypeIdBasicOps.cs new file mode 100644 index 0000000..5d9f1e3 --- /dev/null +++ b/src/FastIDs.TypeId/TypeId.BenchmarksNuget/TypeIdBasicOps.cs @@ -0,0 +1,132 @@ +using System.Text; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Configs; + +namespace TypeId.BenchmarksNuget; + +[MemoryDiagnoser] +[MarkdownExporter] +[MarkdownExporterAttribute.Default] +public class TypeIdBasicOps +{ + [Params(0, 15, 63)] + public int TypeLength; + + private string _typeIdString = ""; + private FastIDs.TypeId.TypeIdDecoded _typeIdDecoded; + private FastIDs.TypeId.TypeId _typeId; + private string _prefix = ""; + + private readonly string _prefixFull; + private readonly Guid _uuidV7; + + public TypeIdBasicOps() + { + var random = new Random(42); + var sb = new StringBuilder(63); + for (var i = 0; i < 63; i++) + { + var letter = (char) random.Next('a', 'z'); + sb.Append(letter); + } + _prefixFull = sb.ToString(); + _uuidV7 = new Guid("01890a5d-ac96-774b-bcce-b302099a8057"); + } + + [GlobalSetup] + public void Setup() + { + _prefix = _prefixFull[..TypeLength]; + _typeIdDecoded = FastIDs.TypeId.TypeId.FromUuidV7(_prefix, _uuidV7); + _typeId = _typeIdDecoded.Encode(); + _typeIdString = _typeId.ToString(); + } + + [Benchmark] + public FastIDs.TypeId.TypeId Parse() + { + return FastIDs.TypeId.TypeId.Parse(_typeIdString); + } + + [Benchmark] + public FastIDs.TypeId.TypeId TryParse() + { + FastIDs.TypeId.TypeId.TryParse(_typeIdString, out var typeId); + return typeId; + } + + [Benchmark] + public FastIDs.TypeId.TypeIdDecoded Decode() + { + return _typeId.Decode(); + } + + [Benchmark] + public FastIDs.TypeId.TypeId Encode() + { + return _typeIdDecoded.Encode(); + } + + [Benchmark] + public FastIDs.TypeId.TypeIdDecoded Generate() + { + return FastIDs.TypeId.TypeId.New(_prefix); + } + + [Benchmark] + public FastIDs.TypeId.TypeIdDecoded GenerateUnsafe() + { + return FastIDs.TypeId.TypeId.New(_prefix, false); + } + + [Benchmark] + public string DecodedToString() + { + return _typeIdDecoded.ToString(); + } + + [Benchmark] + public string EncodedToString() + { + return _typeId.ToString(); + } + + [Benchmark] + public DateTimeOffset TimestampFromDecoded() + { + return _typeIdDecoded.GetTimestamp(); + } + + [Benchmark] + public string SuffixFromDecoded() + { + return _typeIdDecoded.GetSuffix(); + } + + [Benchmark] + public char SuffixSpanFromDecoded() + { + const int suffixLength = 26; + Span buffer = stackalloc char[suffixLength]; + var charsWritten = _typeIdDecoded.GetSuffix(buffer); + return buffer[charsWritten - 1]; + } + + [Benchmark] + public ReadOnlySpan SuffixSpanFromEncoded() + { + return _typeId.Suffix; + } + + [Benchmark] + public string TypeFromDecoded() + { + return _typeIdDecoded.Type; + } + + [Benchmark] + public ReadOnlySpan TypeFromEncoded() + { + return _typeId.Type; + } +} \ No newline at end of file diff --git a/src/FastIDs.TypeId/TypeId.BenchmarksNuget/TypeIdWorkflows.cs b/src/FastIDs.TypeId/TypeId.BenchmarksNuget/TypeIdWorkflows.cs new file mode 100644 index 0000000..d78f4d5 --- /dev/null +++ b/src/FastIDs.TypeId/TypeId.BenchmarksNuget/TypeIdWorkflows.cs @@ -0,0 +1,58 @@ +using System.Text; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Configs; + +namespace TypeId.BenchmarksNuget; + +[MemoryDiagnoser] +[MarkdownExporter] +[MarkdownExporterAttribute.Default] +public class TypeIdWorkflows +{ + [Params(0, 15, 63)] + public int TypeLength; + + private string _typeIdString = ""; + private FastIDs.TypeId.TypeIdDecoded _typeIdDecoded; + private FastIDs.TypeId.TypeId _typeId; + private string _prefix = ""; + + private readonly string _prefixFull; + private readonly Guid _uuidV7; + + public TypeIdWorkflows() + { + var random = new Random(42); + var sb = new StringBuilder(63); + for (var i = 0; i < 63; i++) + { + var letter = (char) random.Next('a', 'z'); + sb.Append(letter); + } + _prefixFull = sb.ToString(); + _uuidV7 = new Guid("01890a5d-ac96-774b-bcce-b302099a8057"); + } + + [GlobalSetup] + public void Setup() + { + _prefix = _prefixFull[..TypeLength]; + _typeIdDecoded = FastIDs.TypeId.TypeId.FromUuidV7(_prefix, _uuidV7); + _typeId = _typeIdDecoded.Encode(); + _typeIdString = _typeId.ToString(); + } + + [Benchmark] + public string Generate_ToString() + { + var typeIdDecoded = FastIDs.TypeId.TypeId.New(_prefix); + return typeIdDecoded.ToString(); + } + + [Benchmark] + public string Parse_ToString() + { + var typeId = FastIDs.TypeId.TypeId.Parse(_typeIdString); + return typeId.ToString(); + } +} \ No newline at end of file