From e2ad4c8d53ac89216dca3f631e081d2fc375bfc4 Mon Sep 17 00:00:00 2001 From: Joyless <65855333+Joy-less@users.noreply.github.com> Date: Sun, 26 Jan 2025 18:37:29 +0000 Subject: [PATCH 1/3] Update target frameworks --- .../BitFaster.Caching.Benchmarks.csproj | 2 +- .../DataStructureBenchmarks.cs | 2 +- BitFaster.Caching.Benchmarks/DisposerBench.cs | 2 +- .../DrainBenchmarks.cs | 4 +- .../Lfu/CmSketchFlat.cs | 8 +-- .../Lfu/CmSketchNoPin.cs | 17 +++-- .../TimeBenchmarks.cs | 2 +- .../BitFaster.Caching.HitRateAnalysis.csproj | 2 +- ...itFaster.Caching.ThroughputAnalysis.csproj | 2 +- .../BitFaster.Caching.UnitTests.Std.csproj | 4 +- .../DurationTests.cs | 2 +- .../Atomic/AtomicFactoryAsyncCacheTests.cs | 8 +-- .../Atomic/AtomicFactoryCacheTests.cs | 4 +- .../BitFaster.Caching.UnitTests.csproj | 4 +- .../Buffers/MpscBoundedBufferTests.cs | 2 +- .../CacheEventProxyBaseTests.cs | 4 +- .../CacheEventsTests.cs | 2 +- .../CacheMetricsTests.cs | 2 +- BitFaster.Caching.UnitTests/CacheTests.cs | 2 +- BitFaster.Caching.UnitTests/DurationTests.cs | 8 +-- BitFaster.Caching.UnitTests/Intrinsics.cs | 12 +--- .../Lfu/ConcurrentLfuCoreTests.cs | 6 +- .../Lfu/ConcurrentLfuTests.cs | 2 +- .../Lfu/TimerWheelTests.cs | 2 +- .../Lru/ClassicLruTests.cs | 2 +- .../Lru/ConcurrentLruTests.cs | 4 +- .../Lru/TLruTickCount64PolicyTests .cs | 2 +- .../Lru/TelemetryPolicyTests.cs | 2 +- .../Lru/TlruStopwatchPolicyTests.cs | 2 +- .../ScopedAsyncCacheTestBase.cs | 4 +- .../ScopedAsyncCacheTests.cs | 2 +- .../ScopedCacheTestBase.cs | 4 +- BitFaster.Caching/AssemblyInfo.cs | 2 +- .../Atomic/AtomicFactoryAsyncCache.cs | 2 +- .../Atomic/AtomicFactoryCache.cs | 2 +- .../Atomic/ConcurrentDictionaryExtensions.cs | 4 +- BitFaster.Caching/BitFaster.Caching.csproj | 4 +- BitFaster.Caching/BitOps.cs | 10 +-- BitFaster.Caching/Buffers/ArrayExtensions.cs | 2 +- BitFaster.Caching/CacheEventProxyBase.cs | 4 +- BitFaster.Caching/Duration.cs | 69 +------------------ BitFaster.Caching/IAsyncCache.cs | 4 +- BitFaster.Caching/IAsyncCacheExt.cs | 2 +- BitFaster.Caching/ICache.cs | 4 +- BitFaster.Caching/ICacheEvents.cs | 2 +- BitFaster.Caching/ICacheExt.cs | 2 +- BitFaster.Caching/ICacheMetrics.cs | 2 +- BitFaster.Caching/IScoped.cs | 4 -- BitFaster.Caching/IScopedAsyncCache.cs | 4 +- BitFaster.Caching/IScopedCache.cs | 4 +- BitFaster.Caching/Intrinsics.cs | 17 ++--- BitFaster.Caching/Lfu/CmSketchCore.cs | 29 ++++---- BitFaster.Caching/Lfu/ConcurrentLfuCore.cs | 8 +-- BitFaster.Caching/Lru/ClassicLru.cs | 2 +- BitFaster.Caching/Lru/ConcurrentLruCore.cs | 14 ++-- BitFaster.Caching/Lru/ITelemetryPolicy.cs | 2 +- BitFaster.Caching/NullableAttributes.cs | 4 +- BitFaster.Caching/Padding.cs | 6 +- BitFaster.Caching/ScopedAsyncCache.cs | 2 +- 59 files changed, 124 insertions(+), 214 deletions(-) diff --git a/BitFaster.Caching.Benchmarks/BitFaster.Caching.Benchmarks.csproj b/BitFaster.Caching.Benchmarks/BitFaster.Caching.Benchmarks.csproj index aa79c2b9..4930d7e5 100644 --- a/BitFaster.Caching.Benchmarks/BitFaster.Caching.Benchmarks.csproj +++ b/BitFaster.Caching.Benchmarks/BitFaster.Caching.Benchmarks.csproj @@ -3,7 +3,7 @@ Exe latest - net6.0;net8.0 + net8.0;net9.0 True true diff --git a/BitFaster.Caching.Benchmarks/DataStructureBenchmarks.cs b/BitFaster.Caching.Benchmarks/DataStructureBenchmarks.cs index b8b0d0fd..c938870f 100644 --- a/BitFaster.Caching.Benchmarks/DataStructureBenchmarks.cs +++ b/BitFaster.Caching.Benchmarks/DataStructureBenchmarks.cs @@ -10,7 +10,7 @@ namespace BitFaster.Caching.Benchmarks #if Windows [SimpleJob(RuntimeMoniker.Net48)] #endif - [SimpleJob(RuntimeMoniker.Net60)] + [SimpleJob(RuntimeMoniker.Net90)] [MemoryDiagnoser(displayGenColumns: false)] public class DataStructureBenchmarks { diff --git a/BitFaster.Caching.Benchmarks/DisposerBench.cs b/BitFaster.Caching.Benchmarks/DisposerBench.cs index b17fd36d..3c45e4b9 100644 --- a/BitFaster.Caching.Benchmarks/DisposerBench.cs +++ b/BitFaster.Caching.Benchmarks/DisposerBench.cs @@ -11,7 +11,7 @@ namespace BitFaster.Caching.Benchmarks [DisassemblyDiagnoser(printSource: true, maxDepth: 3)] [SimpleJob(RuntimeMoniker.Net48)] #endif - [SimpleJob(RuntimeMoniker.Net60)] + [SimpleJob(RuntimeMoniker.Net90)] [MemoryDiagnoser(displayGenColumns: false)] [HideColumns("Job", "Median", "RatioSD", "Alloc Ratio")] public class DisposerBench diff --git a/BitFaster.Caching.Benchmarks/DrainBenchmarks.cs b/BitFaster.Caching.Benchmarks/DrainBenchmarks.cs index 51306c91..807bf500 100644 --- a/BitFaster.Caching.Benchmarks/DrainBenchmarks.cs +++ b/BitFaster.Caching.Benchmarks/DrainBenchmarks.cs @@ -10,7 +10,7 @@ namespace BitFaster.Caching.Benchmarks [DisassemblyDiagnoser(printSource: true, maxDepth: 3)] [SimpleJob(RuntimeMoniker.Net48)] #endif - [SimpleJob(RuntimeMoniker.Net60)] + [SimpleJob(RuntimeMoniker.Net90)] [HideColumns("Job", "Median", "RatioSD", "Alloc Ratio")] public class DrainBenchmarks { @@ -187,7 +187,7 @@ public void Add() public void DrainArray() { Add(); -#if NETCOREAPP3_1_OR_GREATER +#if NET buffer.DrainTo(output.AsSpan()); #else buffer.DrainTo(new ArraySegment(output)); diff --git a/BitFaster.Caching.Benchmarks/Lfu/CmSketchFlat.cs b/BitFaster.Caching.Benchmarks/Lfu/CmSketchFlat.cs index f0523066..b70ec3af 100644 --- a/BitFaster.Caching.Benchmarks/Lfu/CmSketchFlat.cs +++ b/BitFaster.Caching.Benchmarks/Lfu/CmSketchFlat.cs @@ -4,7 +4,7 @@ using System.Text; using System.Threading.Tasks; -#if NETCOREAPP3_1_OR_GREATER +#if NET using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; #endif @@ -53,7 +53,7 @@ public CmSketchFlat(long maximumSize, IEqualityComparer comparer) /// The estimated frequency of the value. public int EstimateFrequency(T value) { -#if !NETCOREAPP3_1_OR_GREATER +#if !NET return EstimateFrequencyStd(value); #else @@ -76,7 +76,7 @@ public int EstimateFrequency(T value) /// The value. public void Increment(T value) { -#if !NETCOREAPP3_1_OR_GREATER +#if !NET IncrementStd(value); #else @@ -207,7 +207,7 @@ private int Spread(int x) return (int)((y >> 16) ^ y); } -#if NETCOREAPP3_1_OR_GREATER +#if NET private unsafe int EstimateFrequencyAvx(T value) { int hash = Spread(comparer.GetHashCode(value)); diff --git a/BitFaster.Caching.Benchmarks/Lfu/CmSketchNoPin.cs b/BitFaster.Caching.Benchmarks/Lfu/CmSketchNoPin.cs index fdc8629a..8b1365a5 100644 --- a/BitFaster.Caching.Benchmarks/Lfu/CmSketchNoPin.cs +++ b/BitFaster.Caching.Benchmarks/Lfu/CmSketchNoPin.cs @@ -1,10 +1,9 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; -#if NET6_0_OR_GREATER +#if NET using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; @@ -57,7 +56,7 @@ public CmSketchNoPin(long maximumSize, IEqualityComparer comparer) /// The estimated frequency of the value. public int EstimateFrequency(T value) { -#if NET48 +#if NETSTANDARD return EstimateFrequencyStd(value); #else @@ -67,7 +66,7 @@ public int EstimateFrequency(T value) { return EstimateFrequencyAvx(value); } -#if NET6_0_OR_GREATER +#if NET else if (isa.IsArm64Supported) { return EstimateFrequencyArm(value); @@ -86,7 +85,7 @@ public int EstimateFrequency(T value) /// The value. public void Increment(T value) { -#if NET48 +#if NETSTANDARD IncrementStd(value); #else @@ -96,7 +95,7 @@ public void Increment(T value) { IncrementAvx(value); } -#if NET6_0_OR_GREATER +#if NET else if (isa.IsArm64Supported) { IncrementArm(value); @@ -233,7 +232,7 @@ private void Reset() size = (size - (count0 >> 2)) >> 1; } -#if NET6_0_OR_GREATER +#if NET private unsafe int EstimateFrequencyAvx(T value) { int blockHash = Spread(comparer.GetHashCode(value)); @@ -267,7 +266,7 @@ private unsafe int EstimateFrequencyAvx(T value) .AsUInt16(); // set the zeroed high parts of the long value to ushort.Max -#if NET6_0 +#if NET count = Avx2.Blend(count, Vector128.AllBitsSet, 0b10101010); #else count = Avx2.Blend(count, Vector128.Create(ushort.MaxValue), 0b10101010); @@ -333,7 +332,7 @@ private unsafe void IncrementAvx(T value) } #endif -#if NET6_0_OR_GREATER +#if NET [MethodImpl(MethodImplOptions.AggressiveInlining)] private unsafe void IncrementArm(T value) { diff --git a/BitFaster.Caching.Benchmarks/TimeBenchmarks.cs b/BitFaster.Caching.Benchmarks/TimeBenchmarks.cs index e4514582..f15bde49 100644 --- a/BitFaster.Caching.Benchmarks/TimeBenchmarks.cs +++ b/BitFaster.Caching.Benchmarks/TimeBenchmarks.cs @@ -41,7 +41,7 @@ public int EnvironmentTickCount() [Benchmark()] public long EnvironmentTickCount64() { -#if NETCOREAPP3_0_OR_GREATER +#if NET return Environment.TickCount64; #else return 0; diff --git a/BitFaster.Caching.HitRateAnalysis/BitFaster.Caching.HitRateAnalysis.csproj b/BitFaster.Caching.HitRateAnalysis/BitFaster.Caching.HitRateAnalysis.csproj index 983b9059..181a3879 100644 --- a/BitFaster.Caching.HitRateAnalysis/BitFaster.Caching.HitRateAnalysis.csproj +++ b/BitFaster.Caching.HitRateAnalysis/BitFaster.Caching.HitRateAnalysis.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net9.0 true true true diff --git a/BitFaster.Caching.ThroughputAnalysis/BitFaster.Caching.ThroughputAnalysis.csproj b/BitFaster.Caching.ThroughputAnalysis/BitFaster.Caching.ThroughputAnalysis.csproj index f1f31f1c..a0a597e8 100644 --- a/BitFaster.Caching.ThroughputAnalysis/BitFaster.Caching.ThroughputAnalysis.csproj +++ b/BitFaster.Caching.ThroughputAnalysis/BitFaster.Caching.ThroughputAnalysis.csproj @@ -2,7 +2,7 @@ Exe - net6.0;net8.0 + net8.0;net9.0 False 2.0.0 true diff --git a/BitFaster.Caching.UnitTests.Std/BitFaster.Caching.UnitTests.Std.csproj b/BitFaster.Caching.UnitTests.Std/BitFaster.Caching.UnitTests.Std.csproj index 1f91474b..ffb9e912 100644 --- a/BitFaster.Caching.UnitTests.Std/BitFaster.Caching.UnitTests.Std.csproj +++ b/BitFaster.Caching.UnitTests.Std/BitFaster.Caching.UnitTests.Std.csproj @@ -1,8 +1,8 @@  - net6.0 - 9.0 + net9.0 + latest diff --git a/BitFaster.Caching.UnitTests.Std/DurationTests.cs b/BitFaster.Caching.UnitTests.Std/DurationTests.cs index 7a58df9f..0456ee38 100644 --- a/BitFaster.Caching.UnitTests.Std/DurationTests.cs +++ b/BitFaster.Caching.UnitTests.Std/DurationTests.cs @@ -25,7 +25,7 @@ public void SinceEpoch() // On .NET Standard, only windows uses TickCount64 if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - Duration.SinceEpoch().raw.Should().BeCloseTo(Duration.GetTickCount64(), 15); + Duration.SinceEpoch().raw.Should().BeCloseTo(Environment.TickCount64, 15); } else { diff --git a/BitFaster.Caching.UnitTests/Atomic/AtomicFactoryAsyncCacheTests.cs b/BitFaster.Caching.UnitTests/Atomic/AtomicFactoryAsyncCacheTests.cs index 7459de31..e8dbacfa 100644 --- a/BitFaster.Caching.UnitTests/Atomic/AtomicFactoryAsyncCacheTests.cs +++ b/BitFaster.Caching.UnitTests/Atomic/AtomicFactoryAsyncCacheTests.cs @@ -91,8 +91,8 @@ public void WhenRemovedEventHandlerIsRegisteredItIsFired() this.removedItems.First().Key.Should().Be(1); } - // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +// backcompat: remove conditional compile +#if NET [Fact] public void WhenUpdatedEventHandlerIsRegisteredItIsFired() { @@ -258,8 +258,8 @@ public async Task WhenFactoryThrowsEmptyKeyIsNotEnumerable() cache.Keys.Count().Should().Be(0); } - // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +// backcompat: remove conditional compile +#if NET [Fact] public void WhenRemovedValueIsReturned() { diff --git a/BitFaster.Caching.UnitTests/Atomic/AtomicFactoryCacheTests.cs b/BitFaster.Caching.UnitTests/Atomic/AtomicFactoryCacheTests.cs index 0c8bd66c..d2434418 100644 --- a/BitFaster.Caching.UnitTests/Atomic/AtomicFactoryCacheTests.cs +++ b/BitFaster.Caching.UnitTests/Atomic/AtomicFactoryCacheTests.cs @@ -79,8 +79,8 @@ public void WhenRemovedEventHandlerIsRegisteredItIsFired() this.removedItems.First().Key.Should().Be(1); } - // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +// backcompat: remove conditional compile +#if NET [Fact] public void WhenRemovedValueIsReturned() { diff --git a/BitFaster.Caching.UnitTests/BitFaster.Caching.UnitTests.csproj b/BitFaster.Caching.UnitTests/BitFaster.Caching.UnitTests.csproj index 93a5a179..03f9fb9a 100644 --- a/BitFaster.Caching.UnitTests/BitFaster.Caching.UnitTests.csproj +++ b/BitFaster.Caching.UnitTests/BitFaster.Caching.UnitTests.csproj @@ -1,8 +1,8 @@ - net48;netcoreapp3.1;net6.0 - 9.0 + net48;net8.0;net9.0 + latest diff --git a/BitFaster.Caching.UnitTests/Buffers/MpscBoundedBufferTests.cs b/BitFaster.Caching.UnitTests/Buffers/MpscBoundedBufferTests.cs index a4a65242..ad0adc8d 100644 --- a/BitFaster.Caching.UnitTests/Buffers/MpscBoundedBufferTests.cs +++ b/BitFaster.Caching.UnitTests/Buffers/MpscBoundedBufferTests.cs @@ -100,7 +100,7 @@ public void WhenBufferEmptyDrainReturnsZero() buffer.DrainTo(output).Should().Be(0); } -#if NETCOREAPP3_0_OR_GREATER +#if NET [Fact] public void WhenBufferContainsItemsDrainArrayTakesItems() { diff --git a/BitFaster.Caching.UnitTests/CacheEventProxyBaseTests.cs b/BitFaster.Caching.UnitTests/CacheEventProxyBaseTests.cs index 6cbd4908..f82fdc1c 100644 --- a/BitFaster.Caching.UnitTests/CacheEventProxyBaseTests.cs +++ b/BitFaster.Caching.UnitTests/CacheEventProxyBaseTests.cs @@ -55,7 +55,7 @@ public void WhenTwoRemovedEventHandlersAddedThenOneRemovedEventIsFired() } // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET [Fact] public void WheUpdatedEventHandlerIsRegisteredItIsFired() { @@ -155,7 +155,7 @@ public void WhenUpdatedEventHandlerIsRegisteredAndProxyUsesDefaultUpdateTranslat this.testCacheEvents.FireUpdated(1, new AtomicFactory(2), new AtomicFactory(3)); -#if NETCOREAPP3_0_OR_GREATER +#if NET this.updatedItems.First().Key.Should().Be(1); #else this.updatedItems.Should().BeEmpty(); diff --git a/BitFaster.Caching.UnitTests/CacheEventsTests.cs b/BitFaster.Caching.UnitTests/CacheEventsTests.cs index e51002d2..bf7e6b6a 100644 --- a/BitFaster.Caching.UnitTests/CacheEventsTests.cs +++ b/BitFaster.Caching.UnitTests/CacheEventsTests.cs @@ -5,7 +5,7 @@ namespace BitFaster.Caching.UnitTests { // backcompat: remove -#if NETCOREAPP3_1_OR_GREATER +#if NET public class CacheEventsTests { [Fact] diff --git a/BitFaster.Caching.UnitTests/CacheMetricsTests.cs b/BitFaster.Caching.UnitTests/CacheMetricsTests.cs index 62bf3368..7094d007 100644 --- a/BitFaster.Caching.UnitTests/CacheMetricsTests.cs +++ b/BitFaster.Caching.UnitTests/CacheMetricsTests.cs @@ -6,7 +6,7 @@ namespace BitFaster.Caching.UnitTests { // backcompat: remove -#if NETCOREAPP3_1_OR_GREATER +#if NET public class CacheMetricsTests { [Fact] diff --git a/BitFaster.Caching.UnitTests/CacheTests.cs b/BitFaster.Caching.UnitTests/CacheTests.cs index 5cdeafa0..166a17a5 100644 --- a/BitFaster.Caching.UnitTests/CacheTests.cs +++ b/BitFaster.Caching.UnitTests/CacheTests.cs @@ -12,7 +12,7 @@ namespace BitFaster.Caching.UnitTests public class CacheTests { // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET [Fact] public void WhenCacheInterfaceDefaultGetOrAddFallback() { diff --git a/BitFaster.Caching.UnitTests/DurationTests.cs b/BitFaster.Caching.UnitTests/DurationTests.cs index 38fbce72..dd4f3bd5 100644 --- a/BitFaster.Caching.UnitTests/DurationTests.cs +++ b/BitFaster.Caching.UnitTests/DurationTests.cs @@ -22,7 +22,7 @@ public DurationTests(ITestOutputHelper testOutputHelper) [Fact] public void SinceEpoch() { -#if NETCOREAPP3_0_OR_GREATER +#if NET if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { // eps is 1/200 of a second @@ -36,7 +36,7 @@ public void SinceEpoch() #else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - Duration.SinceEpoch().raw.Should().BeCloseTo(Duration.GetTickCount64(), 15); + Duration.SinceEpoch().raw.Should().BeCloseTo(Environment.TickCount, 15); } else { @@ -50,7 +50,7 @@ public void SinceEpoch() [Fact] public void ToTimeSpan() { -#if NETCOREAPP3_0_OR_GREATER +#if NET if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { new Duration(100).ToTimeSpan().Should().BeCloseTo(new TimeSpan(100), TimeSpan.FromMilliseconds(50)); @@ -75,7 +75,7 @@ public void ToTimeSpan() [Fact] public void FromTimeSpan() { -#if NETCOREAPP3_0_OR_GREATER +#if NET if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { Duration.FromTimeSpan(TimeSpan.FromSeconds(1)).raw diff --git a/BitFaster.Caching.UnitTests/Intrinsics.cs b/BitFaster.Caching.UnitTests/Intrinsics.cs index ebbe194a..38ee9c30 100644 --- a/BitFaster.Caching.UnitTests/Intrinsics.cs +++ b/BitFaster.Caching.UnitTests/Intrinsics.cs @@ -1,7 +1,5 @@ -#if NETCOREAPP3_1_OR_GREATER +#if NET using System.Runtime.Intrinsics.X86; -#endif -#if NET6_0_OR_GREATER using System.Runtime.Intrinsics.Arm; #endif @@ -13,15 +11,9 @@ public static class Intrinsics { public static void SkipAvxIfNotSupported() { -#if NETCOREAPP3_1_OR_GREATER - #if NET6_0_OR_GREATER +#if NET // when we are trying to test Avx2/Arm64, skip the test if it's not supported Skip.If(typeof(I) == typeof(DetectIsa) && !(Avx2.IsSupported || AdvSimd.Arm64.IsSupported)); - #else - // when we are trying to test Avx2, skip the test if it's not supported - Skip.If(typeof(I) == typeof(DetectIsa) && !Avx2.IsSupported); - #endif - #else Skip.If(true); #endif diff --git a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuCoreTests.cs b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuCoreTests.cs index f3318658..efb2f96e 100644 --- a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuCoreTests.cs +++ b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuCoreTests.cs @@ -41,7 +41,7 @@ public void WhenKeyIsRequestedItIsCreatedAndCached() valueFactory.timesCalled.Should().Be(1); result1.Should().Be(result2); } -#if NETCOREAPP3_0_OR_GREATER +#if NET [Fact] public void WhenKeyIsRequestedWithArgItIsCreatedAndCached() { @@ -63,7 +63,7 @@ public async Task WhenKeyIsRequesteItIsCreatedAndCachedAsync() result1.Should().Be(result2); } -#if NETCOREAPP3_0_OR_GREATER +#if NET [Fact] public async Task WhenKeyIsRequestedWithArgItIsCreatedAndCachedAsync() { @@ -105,7 +105,7 @@ public void WhenKeyExistsTryRemoveRemovesItem() lfu.TryGet(1, out _).Should().BeFalse(); } -#if NETCOREAPP3_0_OR_GREATER +#if NET [Fact] public void WhenKeyExistsTryRemoveReturnsValue() { diff --git a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs index 0f3756bc..c43da509 100644 --- a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs +++ b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs @@ -477,7 +477,7 @@ public void WhenWriteBufferIsFullAddDoesMaintenance() } // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET [Fact] public void WhenWriteBufferIsFullUpdatesAreDropped() { diff --git a/BitFaster.Caching.UnitTests/Lfu/TimerWheelTests.cs b/BitFaster.Caching.UnitTests/Lfu/TimerWheelTests.cs index 25bac835..5b7334ff 100644 --- a/BitFaster.Caching.UnitTests/Lfu/TimerWheelTests.cs +++ b/BitFaster.Caching.UnitTests/Lfu/TimerWheelTests.cs @@ -122,7 +122,7 @@ public void WhenAdvanceOverflowsAndItemIsExpiredItemIsEvicted() this.lfuNodeList.Count.Should().Be(0); } -#if NET6_0_OR_GREATER +#if NET [Theory] [MemberData(nameof(ClockData))] public void WhenAdvanceBackwardsNothingIsEvicted(long clock) diff --git a/BitFaster.Caching.UnitTests/Lru/ClassicLruTests.cs b/BitFaster.Caching.UnitTests/Lru/ClassicLruTests.cs index 4b0b790f..28160594 100644 --- a/BitFaster.Caching.UnitTests/Lru/ClassicLruTests.cs +++ b/BitFaster.Caching.UnitTests/Lru/ClassicLruTests.cs @@ -429,7 +429,7 @@ public void WhenKeyDoesNotExistTryUpdateReturnsFalse() } // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET [Fact] public void WhenKeyExistsTryUpdateIncrementsUpdateCount() { diff --git a/BitFaster.Caching.UnitTests/Lru/ConcurrentLruTests.cs b/BitFaster.Caching.UnitTests/Lru/ConcurrentLruTests.cs index e52015d3..d3575345 100644 --- a/BitFaster.Caching.UnitTests/Lru/ConcurrentLruTests.cs +++ b/BitFaster.Caching.UnitTests/Lru/ConcurrentLruTests.cs @@ -733,7 +733,7 @@ public void WhenKeyDoesNotExistTryUpdateReturnsFalse() } // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET [Fact] public void WhenKeyExistsTryUpdateIncrementsUpdateCount() { @@ -812,7 +812,7 @@ public void WhenKeyDoesNotExistAddOrUpdateMaintainsLruOrder() } // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET [Fact] public void WhenItemExistsAddOrUpdateFiresUpdateEvent() { diff --git a/BitFaster.Caching.UnitTests/Lru/TLruTickCount64PolicyTests .cs b/BitFaster.Caching.UnitTests/Lru/TLruTickCount64PolicyTests .cs index 1acb2aaf..2ff71daf 100644 --- a/BitFaster.Caching.UnitTests/Lru/TLruTickCount64PolicyTests .cs +++ b/BitFaster.Caching.UnitTests/Lru/TLruTickCount64PolicyTests .cs @@ -1,4 +1,4 @@ -#if NETCOREAPP3_1_OR_GREATER +#if NET using FluentAssertions; using BitFaster.Caching.Lru; diff --git a/BitFaster.Caching.UnitTests/Lru/TelemetryPolicyTests.cs b/BitFaster.Caching.UnitTests/Lru/TelemetryPolicyTests.cs index f9e0d9f8..200322a7 100644 --- a/BitFaster.Caching.UnitTests/Lru/TelemetryPolicyTests.cs +++ b/BitFaster.Caching.UnitTests/Lru/TelemetryPolicyTests.cs @@ -148,7 +148,7 @@ public void WhenEventSourceIsSetItemUpdatedEventUsesSource() } // backcompat: remove -#if NETCOREAPP3_1_OR_GREATER +#if NET [Fact] public void WhenInterfaceDefaultItemUpdatedRegisteredNoOp() { diff --git a/BitFaster.Caching.UnitTests/Lru/TlruStopwatchPolicyTests.cs b/BitFaster.Caching.UnitTests/Lru/TlruStopwatchPolicyTests.cs index 1b228af4..9eb6d77a 100644 --- a/BitFaster.Caching.UnitTests/Lru/TlruStopwatchPolicyTests.cs +++ b/BitFaster.Caching.UnitTests/Lru/TlruStopwatchPolicyTests.cs @@ -9,7 +9,7 @@ namespace BitFaster.Caching.UnitTests.Lru { // backcompat: remove conditional compile -#if !NETCOREAPP3_1_OR_GREATER +#if !NET public class TlruStopwatchPolicyTests { private readonly TLruLongTicksPolicy policy = new TLruLongTicksPolicy(TimeSpan.FromSeconds(10)); diff --git a/BitFaster.Caching.UnitTests/ScopedAsyncCacheTestBase.cs b/BitFaster.Caching.UnitTests/ScopedAsyncCacheTestBase.cs index 6bd50a76..b8b4ae8a 100644 --- a/BitFaster.Caching.UnitTests/ScopedAsyncCacheTestBase.cs +++ b/BitFaster.Caching.UnitTests/ScopedAsyncCacheTestBase.cs @@ -59,7 +59,7 @@ public void WhenRemovedEventHandlerIsRegisteredItIsFired() } // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET [Fact] public void WhenUpdatedEventHandlerIsRegisteredItIsFired() { @@ -83,7 +83,7 @@ public void WhenKeyDoesNotExistAddOrUpdateAddsNewItem() } // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET [Fact] public async Task WhenKeyDoesNotExistGetOrAddArgAddsValueWithArg() { diff --git a/BitFaster.Caching.UnitTests/ScopedAsyncCacheTests.cs b/BitFaster.Caching.UnitTests/ScopedAsyncCacheTests.cs index 864287c6..0aec2836 100644 --- a/BitFaster.Caching.UnitTests/ScopedAsyncCacheTests.cs +++ b/BitFaster.Caching.UnitTests/ScopedAsyncCacheTests.cs @@ -53,7 +53,7 @@ public async Task GetOrAddAsyncDisposedScopeThrows() } // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET [Fact] public async Task GetOrAddAsyncArgDisposedScopeThrows() { diff --git a/BitFaster.Caching.UnitTests/ScopedCacheTestBase.cs b/BitFaster.Caching.UnitTests/ScopedCacheTestBase.cs index dd41bda2..863c124b 100644 --- a/BitFaster.Caching.UnitTests/ScopedCacheTestBase.cs +++ b/BitFaster.Caching.UnitTests/ScopedCacheTestBase.cs @@ -58,7 +58,7 @@ public void WhenRemovedEventHandlerIsRegisteredItIsFired() } // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET [Fact] public void WhenUpdatedEventHandlerIsRegisteredItIsFired() { @@ -82,7 +82,7 @@ public void WhenKeyDoesNotExistAddOrUpdateAddsNewItem() } // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET [Fact] public void WhenKeyDoesNotExistGetOrAddArgAddsValueWithArg() { diff --git a/BitFaster.Caching/AssemblyInfo.cs b/BitFaster.Caching/AssemblyInfo.cs index fe942190..a33d04a5 100644 --- a/BitFaster.Caching/AssemblyInfo.cs +++ b/BitFaster.Caching/AssemblyInfo.cs @@ -1,6 +1,6 @@ using System.Runtime.CompilerServices; -#if NET6_0_OR_GREATER +#if NET [module: System.Runtime.CompilerServices.SkipLocalsInit] #endif diff --git a/BitFaster.Caching/Atomic/AtomicFactoryAsyncCache.cs b/BitFaster.Caching/Atomic/AtomicFactoryAsyncCache.cs index 7e3c0ce6..4fdefa75 100644 --- a/BitFaster.Caching/Atomic/AtomicFactoryAsyncCache.cs +++ b/BitFaster.Caching/Atomic/AtomicFactoryAsyncCache.cs @@ -113,7 +113,7 @@ public bool TryRemove(K key) } // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET /// /// ///If the value factory is still executing, returns false. diff --git a/BitFaster.Caching/Atomic/AtomicFactoryCache.cs b/BitFaster.Caching/Atomic/AtomicFactoryCache.cs index 0c75390d..36c38968 100644 --- a/BitFaster.Caching/Atomic/AtomicFactoryCache.cs +++ b/BitFaster.Caching/Atomic/AtomicFactoryCache.cs @@ -107,7 +107,7 @@ public bool TryGet(K key, [MaybeNullWhen(false)] out V value) } // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET /// /// ///If the value factory is still executing, returns false. diff --git a/BitFaster.Caching/Atomic/ConcurrentDictionaryExtensions.cs b/BitFaster.Caching/Atomic/ConcurrentDictionaryExtensions.cs index f332435f..0479b720 100644 --- a/BitFaster.Caching/Atomic/ConcurrentDictionaryExtensions.cs +++ b/BitFaster.Caching/Atomic/ConcurrentDictionaryExtensions.cs @@ -124,7 +124,7 @@ public static bool TryRemove(this ConcurrentDictionary>(item.Key, new AtomicFactory(item.Value)); -#if NET6_0_OR_GREATER +#if NET return dictionary.TryRemove(kvp); #else // https://devblogs.microsoft.com/pfxteam/little-known-gems-atomic-conditional-removals-from-concurrentdictionary/ @@ -142,7 +142,7 @@ public static bool TryRemove(this ConcurrentDictionary>(item.Key, new AsyncAtomicFactory(item.Value)); -#if NET6_0_OR_GREATER +#if NET return dictionary.TryRemove(kvp); #else // https://devblogs.microsoft.com/pfxteam/little-known-gems-atomic-conditional-removals-from-concurrentdictionary/ diff --git a/BitFaster.Caching/BitFaster.Caching.csproj b/BitFaster.Caching/BitFaster.Caching.csproj index 55f0e8dc..f55470b7 100644 --- a/BitFaster.Caching/BitFaster.Caching.csproj +++ b/BitFaster.Caching/BitFaster.Caching.csproj @@ -1,8 +1,8 @@ - netstandard2.0;netcoreapp3.1;net6.0 - 11.0 + netstandard2.0;net8.0;net9.0 + latest Alex Peck BitFaster.Caching diff --git a/BitFaster.Caching/BitOps.cs b/BitFaster.Caching/BitOps.cs index 9c35873e..8ca3ebbc 100644 --- a/BitFaster.Caching/BitOps.cs +++ b/BitFaster.Caching/BitOps.cs @@ -34,7 +34,7 @@ internal static long CeilingPowerOfTwo(long x) /// Smallest power of two greater than or equal to x. public static uint CeilingPowerOfTwo(uint x) { -#if NETSTANDARD2_0 +#if NETSTANDARD // https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 --x; x |= x >> 1; @@ -55,7 +55,7 @@ public static uint CeilingPowerOfTwo(uint x) /// Smallest power of two greater than or equal to x. internal static ulong CeilingPowerOfTwo(ulong x) { -#if NETSTANDARD2_0 +#if NETSTANDARD // https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 --x; x |= x >> 1; @@ -87,7 +87,7 @@ internal static int TrailingZeroCount(long x) /// The number of trailing zero bits. internal static int TrailingZeroCount(ulong x) { -#if NETSTANDARD2_0 +#if NETSTANDARD // https://codereview.stackexchange.com/questions/288007/c-bit-utility-functions-popcount-trailing-zeros-count-reverse-all-bits return BitCount(~x & (x - 1)); #else @@ -112,7 +112,7 @@ public static int BitCount(int x) /// The number of 1 bits. public static int BitCount(uint x) { -#if NETSTANDARD2_0 +#if NETSTANDARD var count = 0; while (x != 0) { @@ -143,7 +143,7 @@ public static int BitCount(long x) /// The number of 1 bits. public static int BitCount(ulong x) { -#if NETSTANDARD2_0 +#if NETSTANDARD var count = 0; while (x != 0) { diff --git a/BitFaster.Caching/Buffers/ArrayExtensions.cs b/BitFaster.Caching/Buffers/ArrayExtensions.cs index 9325247b..ab608af2 100644 --- a/BitFaster.Caching/Buffers/ArrayExtensions.cs +++ b/BitFaster.Caching/Buffers/ArrayExtensions.cs @@ -6,7 +6,7 @@ namespace BitFaster.Caching.Buffers // Used to avoid conditional compilation to work with Span and ArraySegment. internal static class ArrayExtensions { -#if NETSTANDARD2_0 +#if NETSTANDARD [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static T[] AsSpanOrArray(this T[] array) { diff --git a/BitFaster.Caching/CacheEventProxyBase.cs b/BitFaster.Caching/CacheEventProxyBase.cs index bdfdb170..0e9f8938 100644 --- a/BitFaster.Caching/CacheEventProxyBase.cs +++ b/BitFaster.Caching/CacheEventProxyBase.cs @@ -62,7 +62,7 @@ private void RegisterUpdated(EventHandler> value itemUpdatedProxy += value; // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET events.ItemUpdated += OnItemUpdated; #endif } @@ -72,7 +72,7 @@ private void UnRegisterUpdated(EventHandler> val this.itemUpdatedProxy -= value; // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET if (this.itemUpdatedProxy == null) { this.events.ItemUpdated -= OnItemUpdated; diff --git a/BitFaster.Caching/Duration.cs b/BitFaster.Caching/Duration.cs index 8cc76832..60f1c925 100644 --- a/BitFaster.Caching/Duration.cs +++ b/BitFaster.Caching/Duration.cs @@ -26,15 +26,6 @@ public readonly struct Duration internal static readonly Duration Zero = new Duration(0); -#if NETCOREAPP3_0_OR_GREATER - private static readonly bool IsMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); -#else - private static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - - [DllImport("kernel32")] - internal static extern long GetTickCount64(); -#endif - internal Duration(long raw) { this.raw = raw; @@ -47,25 +38,7 @@ internal Duration(long raw) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Duration SinceEpoch() { -#if NETCOREAPP3_0_OR_GREATER - if (IsMacOS) - { - return new Duration(Stopwatch.GetTimestamp()); - } - else - { - return new Duration(Environment.TickCount64); - } -#else - if (IsWindows) - { - return new Duration(GetTickCount64()); - } - else - { - return new Duration(Stopwatch.GetTimestamp()); - } -#endif + return new Duration(Stopwatch.GetTimestamp()); } /// @@ -75,25 +48,7 @@ public static Duration SinceEpoch() [MethodImpl(MethodImplOptions.AggressiveInlining)] public TimeSpan ToTimeSpan() { -#if NETCOREAPP3_0_OR_GREATER - if (IsMacOS) - { - return StopwatchTickConverter.FromTicks(raw); - } - else - { - return TimeSpan.FromMilliseconds(raw); - } -#else - if (IsWindows) - { - return TimeSpan.FromMilliseconds(raw); - } - else - { - return StopwatchTickConverter.FromTicks(raw); - } -#endif + return StopwatchTickConverter.FromTicks(raw); } /// @@ -104,25 +59,7 @@ public TimeSpan ToTimeSpan() [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Duration FromTimeSpan(TimeSpan timeSpan) { -#if NETCOREAPP3_0_OR_GREATER - if (IsMacOS) - { - return new Duration(StopwatchTickConverter.ToTicks(timeSpan)); - } - else - { - return new Duration((long)timeSpan.TotalMilliseconds); - } -#else - if (IsWindows) - { - return new Duration((long)timeSpan.TotalMilliseconds); - } - else - { - return new Duration(StopwatchTickConverter.ToTicks(timeSpan)); - } -#endif + return new Duration(StopwatchTickConverter.ToTicks(timeSpan)); } /// diff --git a/BitFaster.Caching/IAsyncCache.cs b/BitFaster.Caching/IAsyncCache.cs index 56a55e5f..2016c63a 100644 --- a/BitFaster.Caching/IAsyncCache.cs +++ b/BitFaster.Caching/IAsyncCache.cs @@ -54,8 +54,8 @@ public interface IAsyncCache : IEnumerable> /// A task that represents the asynchronous GetOrAdd operation. ValueTask GetOrAddAsync(K key, Func> valueFactory); - // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +// backcompat: remove conditional compile +#if !NETSTANDARD /// /// Adds a key/value pair to the cache if the key does not already exist. Returns the new value, or the /// existing value if the key already exists. diff --git a/BitFaster.Caching/IAsyncCacheExt.cs b/BitFaster.Caching/IAsyncCacheExt.cs index 2187be54..32b95c27 100644 --- a/BitFaster.Caching/IAsyncCacheExt.cs +++ b/BitFaster.Caching/IAsyncCacheExt.cs @@ -17,7 +17,7 @@ public interface IAsyncCacheExt : IAsyncCache // certain build targets, for other build targets we will define them within this new interface to avoid breaking // existing clients. // backcompat: remove conditional compile -#if !NETCOREAPP3_0_OR_GREATER +#if NETSTANDARD /// /// Adds a key/value pair to the cache if the key does not already exist. Returns the new value, or the /// existing value if the key already exists. diff --git a/BitFaster.Caching/ICache.cs b/BitFaster.Caching/ICache.cs index 6bd8523a..2702a7cc 100644 --- a/BitFaster.Caching/ICache.cs +++ b/BitFaster.Caching/ICache.cs @@ -54,8 +54,8 @@ public interface ICache : IEnumerable> /// in the cache, or the new value if the key was not in the cache. V GetOrAdd(K key, Func valueFactory); - // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +// backcompat: remove conditional compile +#if NET /// /// Adds a key/value pair to the cache if the key does not already exist. Returns the new value, or the /// existing value if the key already exists. diff --git a/BitFaster.Caching/ICacheEvents.cs b/BitFaster.Caching/ICacheEvents.cs index 80099d06..60a4a9a1 100644 --- a/BitFaster.Caching/ICacheEvents.cs +++ b/BitFaster.Caching/ICacheEvents.cs @@ -13,7 +13,7 @@ public interface ICacheEvents event EventHandler> ItemRemoved; // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET /// /// Occurs when an item is updated. /// diff --git a/BitFaster.Caching/ICacheExt.cs b/BitFaster.Caching/ICacheExt.cs index 612a5b89..5cae0db1 100644 --- a/BitFaster.Caching/ICacheExt.cs +++ b/BitFaster.Caching/ICacheExt.cs @@ -16,7 +16,7 @@ public interface ICacheExt : ICache // certain build targets, for other build targets we will define them within this new interface to avoid breaking // existing clients. // backcompat: remove conditional compile -#if !NETCOREAPP3_0_OR_GREATER +#if !NET /// /// Adds a key/value pair to the cache if the key does not already exist. Returns the new value, or the /// existing value if the key already exists. diff --git a/BitFaster.Caching/ICacheMetrics.cs b/BitFaster.Caching/ICacheMetrics.cs index feb79589..1d1af203 100644 --- a/BitFaster.Caching/ICacheMetrics.cs +++ b/BitFaster.Caching/ICacheMetrics.cs @@ -33,7 +33,7 @@ public interface ICacheMetrics long Evicted { get; } // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET /// /// Gets the total number of updated items. /// diff --git a/BitFaster.Caching/IScoped.cs b/BitFaster.Caching/IScoped.cs index 5a760055..d28db0e6 100644 --- a/BitFaster.Caching/IScoped.cs +++ b/BitFaster.Caching/IScoped.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace BitFaster.Caching { diff --git a/BitFaster.Caching/IScopedAsyncCache.cs b/BitFaster.Caching/IScopedAsyncCache.cs index 47de4532..9661536f 100644 --- a/BitFaster.Caching/IScopedAsyncCache.cs +++ b/BitFaster.Caching/IScopedAsyncCache.cs @@ -59,8 +59,8 @@ public interface IScopedAsyncCache : IEnumerable /// A task that represents the asynchronous ScopedGetOrAdd operation. ValueTask> ScopedGetOrAddAsync(K key, Func>> valueFactory); - // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +// backcompat: remove conditional compile +#if !NETSTANDARD /// /// Adds a key/scoped value pair to the cache if the key does not already exist. Returns a lifetime for either /// the new value, or the existing value if the key already exists. diff --git a/BitFaster.Caching/IScopedCache.cs b/BitFaster.Caching/IScopedCache.cs index 45a0f5c2..c3d62cf5 100644 --- a/BitFaster.Caching/IScopedCache.cs +++ b/BitFaster.Caching/IScopedCache.cs @@ -60,8 +60,8 @@ public interface IScopedCache : IEnumerable>> wh /// the cache. Lifetime ScopedGetOrAdd(K key, Func> valueFactory); - // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +// backcompat: remove conditional compile +#if !NETSTANDARD /// /// Adds a key/scoped value pair to the cache if the key does not already exist. Returns a lifetime for either /// the new value, or the existing value if the key already exists. diff --git a/BitFaster.Caching/Intrinsics.cs b/BitFaster.Caching/Intrinsics.cs index 45908a01..e5e02196 100644 --- a/BitFaster.Caching/Intrinsics.cs +++ b/BitFaster.Caching/Intrinsics.cs @@ -1,8 +1,5 @@ -#if !NETSTANDARD2_0 -using System.Runtime.Intrinsics.X86; -#endif - -#if NET6_0 +#if NET +using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.Arm; #endif @@ -18,7 +15,7 @@ public interface IsaProbe /// bool IsAvx2Supported { get; } -#if NET6_0_OR_GREATER +#if NET /// /// Gets a value indicating whether Arm64 is supported. /// @@ -31,15 +28,15 @@ public interface IsaProbe /// public readonly struct DetectIsa : IsaProbe { -#if NETSTANDARD2_0 +#if NET /// - public bool IsAvx2Supported => false; + public bool IsAvx2Supported => Avx2.IsSupported; #else /// - public bool IsAvx2Supported => Avx2.IsSupported; + public bool IsAvx2Supported => false; #endif -#if NET6_0_OR_GREATER +#if NET /// public bool IsArm64Supported => AdvSimd.Arm64.IsSupported; #else diff --git a/BitFaster.Caching/Lfu/CmSketchCore.cs b/BitFaster.Caching/Lfu/CmSketchCore.cs index 9764c51b..719d6df7 100644 --- a/BitFaster.Caching/Lfu/CmSketchCore.cs +++ b/BitFaster.Caching/Lfu/CmSketchCore.cs @@ -4,14 +4,9 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; - -#if !NETSTANDARD2_0 +#if NET using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; - -#endif - -#if NET6_0_OR_GREATER using System.Runtime.Intrinsics.Arm; #endif @@ -39,7 +34,7 @@ public unsafe class CmSketchCore private const long OneMask = 0x1111111111111111L; private long[] table; -#if NET6_0_OR_GREATER +#if NET private long* tableAddr; #endif private int sampleSize; @@ -76,7 +71,7 @@ public CmSketchCore(long maximumSize, IEqualityComparer comparer) /// The estimated frequency of the value. public int EstimateFrequency(T value) { -#if NETSTANDARD2_0 +#if NETSTANDARD return EstimateFrequencyStd(value); #else @@ -86,7 +81,7 @@ public int EstimateFrequency(T value) { return EstimateFrequencyAvx(value); } -#if NET6_0_OR_GREATER +#if NET else if (isa.IsArm64Supported) { return EstimateFrequencyArm(value); @@ -105,7 +100,7 @@ public int EstimateFrequency(T value) /// The value. public void Increment(T value) { -#if NETSTANDARD2_0 +#if NETSTANDARD IncrementStd(value); #else @@ -115,7 +110,7 @@ public void Increment(T value) { IncrementAvx(value); } -#if NET6_0_OR_GREATER +#if NET else if (isa.IsArm64Supported) { IncrementArm(value); @@ -142,7 +137,7 @@ private void EnsureCapacity(long maximumSize) { int maximum = (int)Math.Min(maximumSize, int.MaxValue >> 1); -#if NET6_0_OR_GREATER +#if NET I isa = default; if (isa.IsAvx2Supported || isa.IsArm64Supported) { @@ -291,7 +286,7 @@ private void Reset() size = (size - (count0 >> 2)) >> 1; } -#if !NETSTANDARD2_0 +#if !NETSTANDARD [MethodImpl(MethodImplOptions.AggressiveInlining)] private unsafe int EstimateFrequencyAvx(T value) { @@ -305,7 +300,7 @@ private unsafe int EstimateFrequencyAvx(T value) Vector256 indexLong = Avx2.PermuteVar8x32(Vector256.Create(index, Vector128.Zero), Vector256.Create(0, 4, 1, 5, 2, 5, 3, 7)).AsUInt64(); -#if NET6_0_OR_GREATER +#if NET long* tablePtr = tableAddr; #else fixed (long* tablePtr = table) @@ -316,7 +311,7 @@ private unsafe int EstimateFrequencyAvx(T value) .AsUInt16(); // set the zeroed high parts of the long value to ushort.Max -#if NET6_0_OR_GREATER +#if NET count = Avx2.Blend(count, Vector128.AllBitsSet, 0b10101010); #else count = Avx2.Blend(count, Vector128.Create(ushort.MaxValue), 0b10101010); @@ -340,7 +335,7 @@ private unsafe void IncrementAvx(T value) Vector256 offsetLong = Avx2.PermuteVar8x32(Vector256.Create(index, Vector128.Zero), Vector256.Create(0, 4, 1, 5, 2, 5, 3, 7)).AsUInt64(); Vector256 mask = Avx2.ShiftLeftLogicalVariable(Vector256.Create(0xfL), offsetLong); -#if NET6_0_OR_GREATER +#if NET long* tablePtr = tableAddr; #else fixed (long* tablePtr = table) @@ -367,7 +362,7 @@ private unsafe void IncrementAvx(T value) } #endif -#if NET6_0_OR_GREATER +#if NET [MethodImpl(MethodImplOptions.AggressiveInlining)] private unsafe void IncrementArm(T value) { diff --git a/BitFaster.Caching/Lfu/ConcurrentLfuCore.cs b/BitFaster.Caching/Lfu/ConcurrentLfuCore.cs index 67f6dbc1..1ca5eac1 100644 --- a/BitFaster.Caching/Lfu/ConcurrentLfuCore.cs +++ b/BitFaster.Caching/Lfu/ConcurrentLfuCore.cs @@ -166,7 +166,7 @@ public void Trim(int itemCount) TakeCandidatesInLruOrder(this.windowLru, candidates, itemCount); } -#if NET6_0_OR_GREATER +#if NET foreach (var candidate in CollectionsMarshal.AsSpan(candidates)) #else foreach (var candidate in candidates) @@ -301,7 +301,7 @@ internal bool TryGetNode(K key, [MaybeNullWhen(false)] out N node) [MethodImpl(MethodImplOptions.NoInlining)] void TryRemove(N node) { -#if NET6_0_OR_GREATER +#if NET if (this.dictionary.TryRemove(new KeyValuePair(node.Key, node))) #else // https://devblogs.microsoft.com/pfxteam/little-known-gems-atomic-conditional-removals-from-concurrentdictionary/ @@ -323,7 +323,7 @@ public bool TryRemove(KeyValuePair item) { var kvp = new KeyValuePair(item.Key, node); -#if NET6_0_OR_GREATER +#if NET if (this.dictionary.TryRemove(kvp)) #else // https://devblogs.microsoft.com/pfxteam/little-known-gems-atomic-conditional-removals-from-concurrentdictionary/ @@ -821,7 +821,7 @@ internal void Evict(LfuNode evictee) // This handles the case where the same key exists in the write buffer both // as added and removed. Remove via KVP ensures we don't remove added nodes. var kvp = new KeyValuePair(evictee.Key, (N)evictee); -#if NET6_0_OR_GREATER +#if NET this.dictionary.TryRemove(kvp); #else ((ICollection>)this.dictionary).Remove(kvp); diff --git a/BitFaster.Caching/Lru/ClassicLru.cs b/BitFaster.Caching/Lru/ClassicLru.cs index b277c9ea..8037f903 100644 --- a/BitFaster.Caching/Lru/ClassicLru.cs +++ b/BitFaster.Caching/Lru/ClassicLru.cs @@ -254,7 +254,7 @@ public bool TryRemove(KeyValuePair item) { var kvp = new KeyValuePair>(item.Key, node); -#if NET6_0_OR_GREATER +#if NET if (this.dictionary.TryRemove(kvp)) #else // https://devblogs.microsoft.com/pfxteam/little-known-gems-atomic-conditional-removals-from-concurrentdictionary/ diff --git a/BitFaster.Caching/Lru/ConcurrentLruCore.cs b/BitFaster.Caching/Lru/ConcurrentLruCore.cs index 937d6747..4f9a2848 100644 --- a/BitFaster.Caching/Lru/ConcurrentLruCore.cs +++ b/BitFaster.Caching/Lru/ConcurrentLruCore.cs @@ -313,8 +313,8 @@ public bool TryRemove(KeyValuePair item) if (EqualityComparer.Default.Equals(existing.Value, item.Value)) { var kvp = new KeyValuePair(item.Key, existing); -#if NET6_0_OR_GREATER - if (this.dictionary.TryRemove(kvp)) +#if NET + if (this.dictionary.TryRemove(kvp)) #else // https://devblogs.microsoft.com/pfxteam/little-known-gems-atomic-conditional-removals-from-concurrentdictionary/ if (((ICollection>)this.dictionary).Remove(kvp)) @@ -391,7 +391,7 @@ public bool TryUpdate(K key, V value) this.itemPolicy.Update(existing); // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET this.telemetryPolicy.OnItemUpdated(existing.Key, oldValue, existing.Value); #endif Disposer.Dispose(oldValue); @@ -784,7 +784,7 @@ private int Move(I item, ItemDestination where, ItemRemovedReason removedReason) var kvp = new KeyValuePair(item.Key, item); -#if NET6_0_OR_GREATER +#if NET if (this.dictionary.TryRemove(kvp)) #else // https://devblogs.microsoft.com/pfxteam/little-known-gems-atomic-conditional-removals-from-concurrentdictionary/ @@ -858,7 +858,7 @@ private static Optional> CreateEvents(ConcurrentLruCore lru) public long Evicted => lru.telemetryPolicy.Evicted; // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET public long Updated => lru.telemetryPolicy.Updated; #endif public int Capacity => lru.Capacity; @@ -897,7 +897,7 @@ public event EventHandler> ItemRemoved } // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET public event EventHandler> ItemUpdated { add { this.lru.telemetryPolicy.ItemUpdated += value; } diff --git a/BitFaster.Caching/Lru/ITelemetryPolicy.cs b/BitFaster.Caching/Lru/ITelemetryPolicy.cs index 27d991cf..eaba7470 100644 --- a/BitFaster.Caching/Lru/ITelemetryPolicy.cs +++ b/BitFaster.Caching/Lru/ITelemetryPolicy.cs @@ -28,7 +28,7 @@ public interface ITelemetryPolicy : ICacheMetrics, ICacheEvents void OnItemRemoved(K key, V value, ItemRemovedReason reason); // backcompat: remove conditional compile -#if NETCOREAPP3_0_OR_GREATER +#if NET /// /// Register the update of an item. /// diff --git a/BitFaster.Caching/NullableAttributes.cs b/BitFaster.Caching/NullableAttributes.cs index a0f91e03..615b0b4f 100644 --- a/BitFaster.Caching/NullableAttributes.cs +++ b/BitFaster.Caching/NullableAttributes.cs @@ -8,7 +8,7 @@ namespace System.Diagnostics.CodeAnalysis { -#if NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48 +#if NETSTANDARD2_0 /// Specifies that null is allowed as an input even if the corresponding type disallows it. [ExcludeFromCodeCoverage] [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] @@ -144,9 +144,7 @@ sealed class DoesNotReturnIfAttribute : Attribute /// Gets the condition parameter value. public bool ParameterValue { get; } } -#endif -#if NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NETCOREAPP3_0 || NETCOREAPP3_1 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48 /// Specifies that the method or property will ensure that the listed field and property members have not-null values. [ExcludeFromCodeCoverage] [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] diff --git a/BitFaster.Caching/Padding.cs b/BitFaster.Caching/Padding.cs index 12656a14..7628d25c 100644 --- a/BitFaster.Caching/Padding.cs +++ b/BitFaster.Caching/Padding.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace BitFaster.Caching +namespace BitFaster.Caching { internal class Padding { diff --git a/BitFaster.Caching/ScopedAsyncCache.cs b/BitFaster.Caching/ScopedAsyncCache.cs index 9fae539d..128c1b6a 100644 --- a/BitFaster.Caching/ScopedAsyncCache.cs +++ b/BitFaster.Caching/ScopedAsyncCache.cs @@ -87,7 +87,7 @@ public async ValueTask> ScopedGetOrAddAsync(K key, Func /// Adds a key/scoped value pair to the cache if the key does not already exist. Returns a lifetime for either /// the new value, or the existing value if the key already exists. From 1321face5d9132b9b8c2d8b97280bb162d50069b Mon Sep 17 00:00:00 2001 From: Joyless <65855333+Joy-less@users.noreply.github.com> Date: Sat, 1 Feb 2025 23:06:13 +0000 Subject: [PATCH 2/3] Improvements based on feedback --- .../Lfu/CmSketchNoPin.cs | 8 +-- BitFaster.Caching/Duration.cs | 1 - BitFaster.Caching/IScopedCache.cs | 2 +- BitFaster.Caching/Lfu/CmSketchCore.cs | 54 +++++++------------ 4 files changed, 23 insertions(+), 42 deletions(-) diff --git a/BitFaster.Caching.Benchmarks/Lfu/CmSketchNoPin.cs b/BitFaster.Caching.Benchmarks/Lfu/CmSketchNoPin.cs index 8b1365a5..423dfb96 100644 --- a/BitFaster.Caching.Benchmarks/Lfu/CmSketchNoPin.cs +++ b/BitFaster.Caching.Benchmarks/Lfu/CmSketchNoPin.cs @@ -56,7 +56,7 @@ public CmSketchNoPin(long maximumSize, IEqualityComparer comparer) /// The estimated frequency of the value. public int EstimateFrequency(T value) { -#if NETSTANDARD +#if NETFRAMEWORK return EstimateFrequencyStd(value); #else @@ -85,7 +85,7 @@ public int EstimateFrequency(T value) /// The value. public void Increment(T value) { -#if NETSTANDARD +#if NETFRAMEWORK IncrementStd(value); #else @@ -266,11 +266,7 @@ private unsafe int EstimateFrequencyAvx(T value) .AsUInt16(); // set the zeroed high parts of the long value to ushort.Max -#if NET count = Avx2.Blend(count, Vector128.AllBitsSet, 0b10101010); -#else - count = Avx2.Blend(count, Vector128.Create(ushort.MaxValue), 0b10101010); -#endif return Avx2.MinHorizontal(count).GetElement(0); } diff --git a/BitFaster.Caching/Duration.cs b/BitFaster.Caching/Duration.cs index 60f1c925..89175365 100644 --- a/BitFaster.Caching/Duration.cs +++ b/BitFaster.Caching/Duration.cs @@ -1,7 +1,6 @@ using System; using System.Diagnostics; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using BitFaster.Caching.Lru; namespace BitFaster.Caching diff --git a/BitFaster.Caching/IScopedCache.cs b/BitFaster.Caching/IScopedCache.cs index c3d62cf5..0673a17f 100644 --- a/BitFaster.Caching/IScopedCache.cs +++ b/BitFaster.Caching/IScopedCache.cs @@ -61,7 +61,7 @@ public interface IScopedCache : IEnumerable>> wh Lifetime ScopedGetOrAdd(K key, Func> valueFactory); // backcompat: remove conditional compile -#if !NETSTANDARD +#if NET /// /// Adds a key/scoped value pair to the cache if the key does not already exist. Returns a lifetime for either /// the new value, or the existing value if the key already exists. diff --git a/BitFaster.Caching/Lfu/CmSketchCore.cs b/BitFaster.Caching/Lfu/CmSketchCore.cs index 719d6df7..94936052 100644 --- a/BitFaster.Caching/Lfu/CmSketchCore.cs +++ b/BitFaster.Caching/Lfu/CmSketchCore.cs @@ -300,25 +300,16 @@ private unsafe int EstimateFrequencyAvx(T value) Vector256 indexLong = Avx2.PermuteVar8x32(Vector256.Create(index, Vector128.Zero), Vector256.Create(0, 4, 1, 5, 2, 5, 3, 7)).AsUInt64(); -#if NET long* tablePtr = tableAddr; -#else - fixed (long* tablePtr = table) -#endif - { - Vector128 count = Avx2.PermuteVar8x32(Avx2.And(Avx2.ShiftRightLogicalVariable(Avx2.GatherVector256(tablePtr, blockOffset, 8), indexLong), Vector256.Create(0xfL)).AsInt32(), Vector256.Create(0, 2, 4, 6, 1, 3, 5, 7)) - .GetLower() - .AsUInt16(); - // set the zeroed high parts of the long value to ushort.Max -#if NET - count = Avx2.Blend(count, Vector128.AllBitsSet, 0b10101010); -#else - count = Avx2.Blend(count, Vector128.Create(ushort.MaxValue), 0b10101010); -#endif + Vector128 count = Avx2.PermuteVar8x32(Avx2.And(Avx2.ShiftRightLogicalVariable(Avx2.GatherVector256(tablePtr, blockOffset, 8), indexLong), Vector256.Create(0xfL)).AsInt32(), Vector256.Create(0, 2, 4, 6, 1, 3, 5, 7)) + .GetLower() + .AsUInt16(); - return Avx2.MinHorizontal(count).GetElement(0); - } + // set the zeroed high parts of the long value to ushort.Max + count = Avx2.Blend(count, Vector128.AllBitsSet, 0b10101010); + + return Avx2.MinHorizontal(count).GetElement(0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -335,29 +326,24 @@ private unsafe void IncrementAvx(T value) Vector256 offsetLong = Avx2.PermuteVar8x32(Vector256.Create(index, Vector128.Zero), Vector256.Create(0, 4, 1, 5, 2, 5, 3, 7)).AsUInt64(); Vector256 mask = Avx2.ShiftLeftLogicalVariable(Vector256.Create(0xfL), offsetLong); -#if NET long* tablePtr = tableAddr; -#else - fixed (long* tablePtr = table) -#endif - { - // Note masked is 'equal' - therefore use AndNot below - Vector256 masked = Avx2.CompareEqual(Avx2.And(Avx2.GatherVector256(tablePtr, blockOffset, 8), mask), mask); - // Mask to zero out non matches (add zero below) - first operand is NOT then AND result (order matters) - Vector256 inc = Avx2.AndNot(masked, Avx2.ShiftLeftLogicalVariable(Vector256.Create(1L), offsetLong)); + // Note masked is 'equal' - therefore use AndNot below + Vector256 masked = Avx2.CompareEqual(Avx2.And(Avx2.GatherVector256(tablePtr, blockOffset, 8), mask), mask); - bool wasInc = Avx2.MoveMask(Avx2.CompareEqual(masked.AsByte(), Vector256.Zero).AsByte()) == unchecked((int)(0b1111_1111_1111_1111_1111_1111_1111_1111)); + // Mask to zero out non matches (add zero below) - first operand is NOT then AND result (order matters) + Vector256 inc = Avx2.AndNot(masked, Avx2.ShiftLeftLogicalVariable(Vector256.Create(1L), offsetLong)); - tablePtr[blockOffset.GetElement(0)] += inc.GetElement(0); - tablePtr[blockOffset.GetElement(1)] += inc.GetElement(1); - tablePtr[blockOffset.GetElement(2)] += inc.GetElement(2); - tablePtr[blockOffset.GetElement(3)] += inc.GetElement(3); + bool wasInc = Avx2.MoveMask(Avx2.CompareEqual(masked.AsByte(), Vector256.Zero).AsByte()) == unchecked((int)0b1111_1111_1111_1111_1111_1111_1111_1111); - if (wasInc && (++size == sampleSize)) - { - Reset(); - } + tablePtr[blockOffset.GetElement(0)] += inc.GetElement(0); + tablePtr[blockOffset.GetElement(1)] += inc.GetElement(1); + tablePtr[blockOffset.GetElement(2)] += inc.GetElement(2); + tablePtr[blockOffset.GetElement(3)] += inc.GetElement(3); + + if (wasInc && (++size == sampleSize)) + { + Reset(); } } #endif From f137cc51dc7dfbb3bf70c5819e7f69a0692decbf Mon Sep 17 00:00:00 2001 From: Joyless <65855333+Joy-less@users.noreply.github.com> Date: Mon, 3 Feb 2025 01:43:03 +0000 Subject: [PATCH 3/3] Re-add micro-optimization --- BitFaster.Caching/Duration.cs | 58 ++++++++++++++++++- .../Lru/StopwatchTickConverter.cs | 2 +- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/BitFaster.Caching/Duration.cs b/BitFaster.Caching/Duration.cs index 89175365..4be15c57 100644 --- a/BitFaster.Caching/Duration.cs +++ b/BitFaster.Caching/Duration.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using BitFaster.Caching.Lru; namespace BitFaster.Caching @@ -23,7 +24,16 @@ public readonly struct Duration // this also avoids overflow when multipling long.MaxValue by 1.0 internal static readonly TimeSpan MaxRepresentable = TimeSpan.FromTicks((long)(long.MaxValue / 100.0d)); - internal static readonly Duration Zero = new Duration(0); + internal static readonly Duration Zero = new(0); + +#if NET + private static readonly bool IsMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); +#else + private static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + + [DllImport("kernel32")] + private static extern long GetTickCount64(); +#endif internal Duration(long raw) { @@ -33,21 +43,49 @@ internal Duration(long raw) /// /// Gets the time since the system epoch. /// - /// A duration + /// A duration. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Duration SinceEpoch() { +#if NET + if (IsMacOS) + { + return new Duration(Stopwatch.GetTimestamp()); + } + + return new Duration(Environment.TickCount64); +#else + if (IsWindows) + { + return new Duration(GetTickCount64()); + } + return new Duration(Stopwatch.GetTimestamp()); +#endif } /// /// Converts the duration to a TimeSpan. /// - /// + /// A TimeSpan. [MethodImpl(MethodImplOptions.AggressiveInlining)] public TimeSpan ToTimeSpan() { +#if NET + if (IsMacOS) + { + return StopwatchTickConverter.FromTicks(raw); + } + + return TimeSpan.FromMilliseconds(raw); +#else + if (IsWindows) + { + return TimeSpan.FromMilliseconds(raw); + } + return StopwatchTickConverter.FromTicks(raw); +#endif } /// @@ -58,7 +96,21 @@ public TimeSpan ToTimeSpan() [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Duration FromTimeSpan(TimeSpan timeSpan) { +#if NET + if (IsMacOS) + { + return new Duration(StopwatchTickConverter.ToTicks(timeSpan)); + } + + return new Duration((long)timeSpan.TotalMilliseconds); +#else + if (IsWindows) + { + return new Duration((long)timeSpan.TotalMilliseconds); + } + return new Duration(StopwatchTickConverter.ToTicks(timeSpan)); +#endif } /// diff --git a/BitFaster.Caching/Lru/StopwatchTickConverter.cs b/BitFaster.Caching/Lru/StopwatchTickConverter.cs index 770e8abb..5de0793b 100644 --- a/BitFaster.Caching/Lru/StopwatchTickConverter.cs +++ b/BitFaster.Caching/Lru/StopwatchTickConverter.cs @@ -6,7 +6,7 @@ namespace BitFaster.Caching.Lru { internal static class StopwatchTickConverter { - // On some platforms (e.g. MacOS), stopwatch and timespan have different resolution + // On some platforms (e.g. MacOS), Stopwatch and TimeSpan have different resolution internal static readonly double stopwatchAdjustmentFactor = Stopwatch.Frequency / (double)TimeSpan.TicksPerSecond; [MethodImpl(MethodImplOptions.AggressiveInlining)]