From c5c56ebd22eeec47dafe4793a38e8c05e5a82fe1 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Fri, 17 May 2024 20:21:00 -0700 Subject: [PATCH 1/4] torn --- BitFaster.Caching.Benchmarks/32bitTImeTest.cs | 75 +++++++++++++++++++ BitFaster.Caching/Lru/Time.cs | 42 ++++++++++- 2 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 BitFaster.Caching.Benchmarks/32bitTImeTest.cs diff --git a/BitFaster.Caching.Benchmarks/32bitTImeTest.cs b/BitFaster.Caching.Benchmarks/32bitTImeTest.cs new file mode 100644 index 00000000..074f0e1b --- /dev/null +++ b/BitFaster.Caching.Benchmarks/32bitTImeTest.cs @@ -0,0 +1,75 @@ +using System; +using System.Runtime.CompilerServices; +using System.Threading; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Jobs; + +namespace BitFaster.Caching.Benchmarks +{ +#if Windows + [DisassemblyDiagnoser(printSource: true, maxDepth: 5)] + [SimpleJob(RuntimeMoniker.Net48)] +#endif + [SimpleJob(RuntimeMoniker.Net60)] + [HideColumns("Job", "Median", "RatioSD", "Alloc Ratio")] + public class _32bitTImeTest + { + private static TimeOrig timeOrig = new TimeOrig(); + private static Time time = new Time(); + + [Benchmark(Baseline =true)] + public long TimeOriginal() + { + return timeOrig.Last; + } + + [Benchmark()] + public long Time2() + { + return time.Last; + } + } + + internal class TimeOrig + { + internal long Last { get; set;} + } + + internal class Time + { + private static readonly bool Is64Bit = Environment.Is64BitProcess; + + private long time; + + /// + /// Gets or sets the last time. + /// + internal long Last + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + if (Is64Bit) + { + return time; + } + else + { + return Interlocked.Read(ref time); + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + if (Is64Bit) + { + time = value; + } + else + { + Interlocked.CompareExchange(ref time, value, time); + } + } + } + } +} diff --git a/BitFaster.Caching/Lru/Time.cs b/BitFaster.Caching/Lru/Time.cs index 7c959306..8ca96c04 100644 --- a/BitFaster.Caching/Lru/Time.cs +++ b/BitFaster.Caching/Lru/Time.cs @@ -1,15 +1,53 @@ -namespace BitFaster.Caching.Lru + +using System; +using System.Runtime.CompilerServices; +using System.Threading; + +namespace BitFaster.Caching.Lru { /// /// During reads, the policy evaluates ShouldDiscard and Touch. To avoid Getting the current time twice /// introduce a simple time class that holds the last time. This is class with a mutable field, because the /// policy structs are readonly. /// + /// + /// This class mitigates torn writes when running on 32-bit systems using Interlocked read and write. + /// internal class Time { + private static readonly bool Is64Bit = Environment.Is64BitProcess; + + private long time; + /// /// Gets or sets the last time. /// - internal long Last { get; set; } + internal long Last + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + if (Is64Bit) + { + return time; + } + else + { + return Interlocked.Read(ref time); + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + if (Is64Bit) + { + time = value; + } + else + { + Interlocked.CompareExchange(ref time, value, time); + } + } + } } } From ee265d15d3224ac2fe7b7df96c684f949a8baf42 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Fri, 17 May 2024 20:55:45 -0700 Subject: [PATCH 2/4] x86 bench --- BitFaster.Caching.Benchmarks/32bitTImeTest.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BitFaster.Caching.Benchmarks/32bitTImeTest.cs b/BitFaster.Caching.Benchmarks/32bitTImeTest.cs index 074f0e1b..6d4dd4f6 100644 --- a/BitFaster.Caching.Benchmarks/32bitTImeTest.cs +++ b/BitFaster.Caching.Benchmarks/32bitTImeTest.cs @@ -9,8 +9,10 @@ namespace BitFaster.Caching.Benchmarks #if Windows [DisassemblyDiagnoser(printSource: true, maxDepth: 5)] [SimpleJob(RuntimeMoniker.Net48)] + [LegacyJitX86Job] #endif [SimpleJob(RuntimeMoniker.Net60)] + [RyuJitX86Job] [HideColumns("Job", "Median", "RatioSD", "Alloc Ratio")] public class _32bitTImeTest { From fd2b3fe7729a06157b3d9cdecd819e9f7349ad7b Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Fri, 17 May 2024 21:22:38 -0700 Subject: [PATCH 3/4] jit --- BitFaster.Caching.Benchmarks/32bitTImeTest.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/BitFaster.Caching.Benchmarks/32bitTImeTest.cs b/BitFaster.Caching.Benchmarks/32bitTImeTest.cs index 6d4dd4f6..431f2e25 100644 --- a/BitFaster.Caching.Benchmarks/32bitTImeTest.cs +++ b/BitFaster.Caching.Benchmarks/32bitTImeTest.cs @@ -12,7 +12,6 @@ namespace BitFaster.Caching.Benchmarks [LegacyJitX86Job] #endif [SimpleJob(RuntimeMoniker.Net60)] - [RyuJitX86Job] [HideColumns("Job", "Median", "RatioSD", "Alloc Ratio")] public class _32bitTImeTest { @@ -30,6 +29,12 @@ public long Time2() { return time.Last; } + + [Benchmark()] + public Duration GetActualTime() + { + return Duration.SinceEpoch(); + } } internal class TimeOrig From a6b6c38ca63199fdefb3bd3a32f6c7596417d58d Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Sat, 18 May 2024 13:46:07 -0700 Subject: [PATCH 4/4] rem bench --- BitFaster.Caching.Benchmarks/32bitTImeTest.cs | 82 ------------------- 1 file changed, 82 deletions(-) delete mode 100644 BitFaster.Caching.Benchmarks/32bitTImeTest.cs diff --git a/BitFaster.Caching.Benchmarks/32bitTImeTest.cs b/BitFaster.Caching.Benchmarks/32bitTImeTest.cs deleted file mode 100644 index 431f2e25..00000000 --- a/BitFaster.Caching.Benchmarks/32bitTImeTest.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Threading; -using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Jobs; - -namespace BitFaster.Caching.Benchmarks -{ -#if Windows - [DisassemblyDiagnoser(printSource: true, maxDepth: 5)] - [SimpleJob(RuntimeMoniker.Net48)] - [LegacyJitX86Job] -#endif - [SimpleJob(RuntimeMoniker.Net60)] - [HideColumns("Job", "Median", "RatioSD", "Alloc Ratio")] - public class _32bitTImeTest - { - private static TimeOrig timeOrig = new TimeOrig(); - private static Time time = new Time(); - - [Benchmark(Baseline =true)] - public long TimeOriginal() - { - return timeOrig.Last; - } - - [Benchmark()] - public long Time2() - { - return time.Last; - } - - [Benchmark()] - public Duration GetActualTime() - { - return Duration.SinceEpoch(); - } - } - - internal class TimeOrig - { - internal long Last { get; set;} - } - - internal class Time - { - private static readonly bool Is64Bit = Environment.Is64BitProcess; - - private long time; - - /// - /// Gets or sets the last time. - /// - internal long Last - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - if (Is64Bit) - { - return time; - } - else - { - return Interlocked.Read(ref time); - } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - if (Is64Bit) - { - time = value; - } - else - { - Interlocked.CompareExchange(ref time, value, time); - } - } - } - } -}