Skip to content

Commit acccf93

Browse files
authored
auto detect high res clock (#334)
* high res clock * auto * test high res clock * cleanup ---------
1 parent df0bb45 commit acccf93

File tree

5 files changed

+93
-32
lines changed

5 files changed

+93
-32
lines changed

BitFaster.Caching.UnitTests/Lru/ConcurrentLruBuilderTests.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,31 @@ public void TestMetricsTLru()
5353
lru.Policy.Eviction.Value.Capacity.Should().Be(128);
5454
}
5555

56+
#if NETCOREAPP3_0_OR_GREATER
57+
[Fact]
58+
public void TestHighResClockTLru()
59+
{
60+
ICache<int, int> lru = new ConcurrentLruBuilder<int, int>()
61+
.WithExpireAfterWrite(TimeSpan.FromMilliseconds(10))
62+
.Build();
63+
64+
lru.Should().BeOfType<ConcurrentLruCore<int, int, LongTickCountLruItem<int, int>, TlruStopwatchPolicy<int, int>, NoTelemetryPolicy<int, int>>>();
65+
lru.Policy.Eviction.Value.Capacity.Should().Be(128);
66+
}
67+
68+
[Fact]
69+
public void TestHighResClockMetricsTLru()
70+
{
71+
ICache<int, int> lru = new ConcurrentLruBuilder<int, int>()
72+
.WithExpireAfterWrite(TimeSpan.FromMilliseconds(10))
73+
.WithMetrics()
74+
.Build();
75+
76+
lru.Should().BeOfType<ConcurrentLruCore<int, int, LongTickCountLruItem<int, int>, TlruStopwatchPolicy<int, int>, TelemetryPolicy<int, int>>>();
77+
lru.Policy.Eviction.Value.Capacity.Should().Be(128);
78+
}
79+
#endif
80+
5681
[Fact]
5782
public void AsAsyncTestFastLru()
5883
{
@@ -98,7 +123,6 @@ public void AsAsyncTestMetricsTLru()
98123
lru.Policy.Eviction.Value.Capacity.Should().Be(128);
99124
}
100125

101-
102126
[Fact]
103127
public void TestComparer()
104128
{

BitFaster.Caching.UnitTests/Lru/ConcurrentTLruTests.cs

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,17 @@
22
using BitFaster.Caching.Lru;
33
using System;
44
using System.Collections.Generic;
5-
using System.Text;
65
using System.Threading.Tasks;
76
using Xunit;
87
using System.Runtime.InteropServices;
98

109
namespace BitFaster.Caching.UnitTests.Lru
1110
{
12-
public class ConcurrentTLruTests
11+
public abstract class ConcurrentTLruTests
1312
{
1413
private readonly TimeSpan timeToLive = TimeSpan.FromMilliseconds(10);
1514
private readonly ICapacityPartition capacity = new EqualCapacityPartition(9);
16-
private ConcurrentTLru<int, string> lru;
15+
private ICache<int, string> lru;
1716

1817
private ValueFactory valueFactory = new ValueFactory();
1918

@@ -27,33 +26,11 @@ private void OnLruItemRemoved(object sender, ItemRemovedEventArgs<int, int> e)
2726
removedItems.Add(e);
2827
}
2928

30-
public ConcurrentTLruTests()
31-
{
32-
lru = new ConcurrentTLru<int, string>(1, capacity, EqualityComparer<int>.Default, timeToLive);
33-
}
34-
35-
[Fact]
36-
public void ConstructWithDefaultCtorReturnsCapacity()
37-
{
38-
var x = new ConcurrentTLru<int, int>(3, TimeSpan.FromSeconds(1));
39-
40-
x.Capacity.Should().Be(3);
41-
}
42-
43-
[Fact]
44-
public void ConstructCapacityCtorReturnsCapacity()
45-
{
46-
var x = new ConcurrentTLru<int, int>(1, 3, EqualityComparer<int>.Default, TimeSpan.FromSeconds(1));
47-
48-
x.Capacity.Should().Be(3);
49-
}
29+
protected abstract ICache<K, V> CreateTLru<K, V>(ICapacityPartition capacity, TimeSpan timeToLive);
5030

51-
[Fact]
52-
public void ConstructPartitionCtorReturnsCapacity()
31+
public ConcurrentTLruTests()
5332
{
54-
var x = new ConcurrentTLru<int, int>(1, new EqualCapacityPartition(3), EqualityComparer<int>.Default, TimeSpan.FromSeconds(1));
55-
56-
x.Capacity.Should().Be(3);
33+
lru = CreateTLru<int, string>(capacity, timeToLive);
5734
}
5835

5936
[Fact]
@@ -101,7 +78,7 @@ public async Task WhenItemIsUpdatedTtlIsExtended()
10178
[Fact]
10279
public void WhenValueEvictedItemRemovedEventIsFired()
10380
{
104-
var lruEvents = new ConcurrentTLru<int, int>(1, new EqualCapacityPartition(6), EqualityComparer<int>.Default, timeToLive);
81+
var lruEvents = CreateTLru<int, int>(new EqualCapacityPartition(6), timeToLive);
10582
lruEvents.Events.Value.ItemRemoved += OnLruItemRemoved;
10683

10784
// First 6 adds
@@ -127,7 +104,7 @@ public void WhenValueEvictedItemRemovedEventIsFired()
127104
[Fact]
128105
public void WhenItemRemovedEventIsUnregisteredEventIsNotFired()
129106
{
130-
var lruEvents = new ConcurrentTLru<int, int>(1, new EqualCapacityPartition(6), EqualityComparer<int>.Default, timeToLive);
107+
var lruEvents = CreateTLru<int, int>(new EqualCapacityPartition(6), timeToLive);
131108
lruEvents.Events.Value.ItemRemoved += OnLruItemRemoved;
132109
lruEvents.Events.Value.ItemRemoved -= OnLruItemRemoved;
133110

@@ -195,9 +172,49 @@ public async Task WhenItemsAreExpiredTrimRemovesExpiredItems()
195172

196173
await Task.Delay(timeToLive * ttlWaitMlutiplier);
197174

198-
lru.Trim(1);
175+
lru.Policy.Eviction.Value.Trim(1);
199176

200177
lru.Count.Should().Be(0);
201178
}
202179
}
180+
181+
public class ConcurrentTLruDefaultClockTests : ConcurrentTLruTests
182+
{
183+
protected override ICache<K, V> CreateTLru<K, V>(ICapacityPartition capacity, TimeSpan timeToLive)
184+
{
185+
return new ConcurrentTLru<K, V>(1, capacity, EqualityComparer<K>.Default, timeToLive);
186+
}
187+
188+
[Fact]
189+
public void ConstructWithDefaultCtorReturnsCapacity()
190+
{
191+
var x = new ConcurrentTLru<int, int>(3, TimeSpan.FromSeconds(1));
192+
193+
x.Capacity.Should().Be(3);
194+
}
195+
196+
[Fact]
197+
public void ConstructCapacityCtorReturnsCapacity()
198+
{
199+
var x = new ConcurrentTLru<int, int>(1, 3, EqualityComparer<int>.Default, TimeSpan.FromSeconds(1));
200+
201+
x.Capacity.Should().Be(3);
202+
}
203+
204+
[Fact]
205+
public void ConstructPartitionCtorReturnsCapacity()
206+
{
207+
var x = new ConcurrentTLru<int, int>(1, new EqualCapacityPartition(3), EqualityComparer<int>.Default, TimeSpan.FromSeconds(1));
208+
209+
x.Capacity.Should().Be(3);
210+
}
211+
}
212+
213+
public class ConcurrentTLruHighResClockTests : ConcurrentTLruTests
214+
{
215+
protected override ICache<K, V> CreateTLru<K, V>(ICapacityPartition capacity, TimeSpan timeToLive)
216+
{
217+
return new ConcurrentLruCore<K, V, LongTickCountLruItem<K, V>, TlruStopwatchPolicy<K, V>, TelemetryPolicy<K, V>>(1, capacity, EqualityComparer<K>.Default, new TlruStopwatchPolicy<K, V>(timeToLive), default);
218+
}
219+
}
203220
}

BitFaster.Caching/Lru/Builder/LruBuilderBase.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ public TBuilder WithMetrics()
7979
public TBuilder WithExpireAfterWrite(TimeSpan expiration)
8080
{
8181
this.info.TimeToExpireAfterWrite = expiration;
82+
83+
#if NETCOREAPP3_0_OR_GREATER
84+
// if the expiration time is less than 2x default precision, switch to high resolution clock automatically.
85+
if (expiration < TimeSpan.FromMilliseconds(32))
86+
{
87+
this.info.WithHighResolutionTime = true;
88+
}
89+
#endif
8290
return this as TBuilder;
8391
}
8492

BitFaster.Caching/Lru/Builder/LruInfo.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,9 @@ internal sealed class LruInfo<K>
1414
public bool WithMetrics { get; set; } = false;
1515

1616
public IEqualityComparer<K> KeyComparer { get; set; } = EqualityComparer<K>.Default;
17+
18+
#if NETCOREAPP3_0_OR_GREATER
19+
public bool WithHighResolutionTime { get; set; } = false;
20+
#endif
1721
}
1822
}

BitFaster.Caching/Lru/ConcurrentLruBuilder.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ public override ICache<K, V> Build()
4141
{
4242
switch (info)
4343
{
44+
#if NETCOREAPP3_0_OR_GREATER
45+
case LruInfo<K> i when i.WithMetrics && i.TimeToExpireAfterWrite.HasValue && i.WithHighResolutionTime:
46+
return new ConcurrentLruCore<K, V, LongTickCountLruItem<K, V>, TlruStopwatchPolicy<K, V>, TelemetryPolicy<K, V>>(
47+
info.ConcurrencyLevel, info.Capacity, info.KeyComparer, new TlruStopwatchPolicy<K, V>(info.TimeToExpireAfterWrite.Value), default);
48+
case LruInfo<K> i when !i.WithMetrics && i.TimeToExpireAfterWrite.HasValue && i.WithHighResolutionTime:
49+
return new ConcurrentLruCore<K, V, LongTickCountLruItem<K, V>, TlruStopwatchPolicy<K, V>, NoTelemetryPolicy<K, V>>(
50+
info.ConcurrencyLevel, info.Capacity, info.KeyComparer, new TlruStopwatchPolicy<K, V>(info.TimeToExpireAfterWrite.Value), default);
51+
#endif
4452
case LruInfo<K> i when i.WithMetrics && !i.TimeToExpireAfterWrite.HasValue:
4553
return new ConcurrentLru<K, V>(info.ConcurrencyLevel, info.Capacity, info.KeyComparer);
4654
case LruInfo<K> i when i.WithMetrics && i.TimeToExpireAfterWrite.HasValue:

0 commit comments

Comments
 (0)