Skip to content

Commit 0f53f0b

Browse files
authored
Inline stopwatch tick conversion (#469)
1 parent d298a14 commit 0f53f0b

File tree

2 files changed

+155
-152
lines changed

2 files changed

+155
-152
lines changed
Lines changed: 152 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,60 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Runtime.InteropServices;
4-
using BitFaster.Caching.Lru;
5-
using FluentAssertions;
6-
using Xunit;
7-
8-
namespace BitFaster.Caching.UnitTests.Lru
9-
{
10-
public class ConcurrentLruAfterAccessTests
11-
{
12-
private readonly TimeSpan timeToLive = TimeSpan.FromMilliseconds(10);
13-
private readonly ICapacityPartition capacity = new EqualCapacityPartition(9);
14-
private ICache<int, string> lru;
15-
16-
private ValueFactory valueFactory = new ValueFactory();
17-
18-
private List<ItemRemovedEventArgs<int, int>> removedItems = new List<ItemRemovedEventArgs<int, int>>();
19-
20-
// on MacOS time measurement seems to be less stable, give longer pause
21-
private int ttlWaitMlutiplier = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 8 : 2;
22-
23-
private void OnLruItemRemoved(object sender, ItemRemovedEventArgs<int, int> e)
24-
{
25-
removedItems.Add(e);
26-
}
27-
28-
public ConcurrentLruAfterAccessTests()
29-
{
30-
lru = new ConcurrentLruBuilder<int, string>()
31-
.WithCapacity(capacity)
32-
.WithExpireAfterAccess(timeToLive)
33-
.Build();
34-
}
35-
36-
[Fact]
37-
public void CanExpireIsTrue()
38-
{
39-
this.lru.Policy.ExpireAfterAccess.HasValue.Should().BeTrue();
40-
}
41-
42-
[Fact]
43-
public void TimeToLiveIsCtorArg()
44-
{
45-
this.lru.Policy.ExpireAfterAccess.Value.TimeToLive.Should().Be(timeToLive);
46-
}
47-
48-
[Fact]
49-
public void WhenItemIsNotExpiredItIsNotRemoved()
50-
{
51-
lru.GetOrAdd(1, valueFactory.Create);
52-
53-
lru.TryGet(1, out var value).Should().BeTrue();
54-
}
55-
56-
[Fact]
57-
public void WhenItemIsExpiredItIsRemoved()
4+
using BitFaster.Caching.Lru;
5+
using FluentAssertions;
6+
using Xunit;
7+
8+
namespace BitFaster.Caching.UnitTests.Lru
9+
{
10+
public class ConcurrentLruAfterAccessTests
11+
{
12+
private readonly TimeSpan timeToLive = TimeSpan.FromMilliseconds(10);
13+
private readonly ICapacityPartition capacity = new EqualCapacityPartition(9);
14+
private ICache<int, string> lru;
15+
16+
private ValueFactory valueFactory = new ValueFactory();
17+
18+
private List<ItemRemovedEventArgs<int, int>> removedItems = new List<ItemRemovedEventArgs<int, int>>();
19+
20+
// on MacOS time measurement seems to be less stable, give longer pause
21+
private int ttlWaitMlutiplier = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 8 : 2;
22+
23+
private void OnLruItemRemoved(object sender, ItemRemovedEventArgs<int, int> e)
24+
{
25+
removedItems.Add(e);
26+
}
27+
28+
public ConcurrentLruAfterAccessTests()
29+
{
30+
lru = new ConcurrentLruBuilder<int, string>()
31+
.WithCapacity(capacity)
32+
.WithExpireAfterAccess(timeToLive)
33+
.Build();
34+
}
35+
36+
[Fact]
37+
public void CanExpireIsTrue()
38+
{
39+
this.lru.Policy.ExpireAfterAccess.HasValue.Should().BeTrue();
40+
}
41+
42+
[Fact]
43+
public void TimeToLiveIsCtorArg()
44+
{
45+
this.lru.Policy.ExpireAfterAccess.Value.TimeToLive.Should().Be(timeToLive);
46+
}
47+
48+
[Fact]
49+
public void WhenItemIsNotExpiredItIsNotRemoved()
50+
{
51+
lru.GetOrAdd(1, valueFactory.Create);
52+
53+
lru.TryGet(1, out var value).Should().BeTrue();
54+
}
55+
56+
[Fact]
57+
public void WhenItemIsExpiredItIsRemoved()
5858
{
5959
Timed.Execute(
6060
lru,
@@ -68,97 +68,97 @@ public void WhenItemIsExpiredItIsRemoved()
6868
{
6969
lru.TryGet(1, out var value).Should().BeFalse();
7070
}
71-
);
72-
}
73-
74-
[Fact]
75-
public void WhenItemIsUpdatedTtlIsExtended()
76-
{
77-
Timed.Execute(
78-
lru,
79-
lru =>
71+
);
72+
}
73+
74+
[Fact]
75+
public void WhenItemIsUpdatedTtlIsExtended()
76+
{
77+
Timed.Execute(
78+
lru,
79+
lru =>
8080
{
81-
lru.GetOrAdd(1, valueFactory.Create);
82-
return lru;
83-
},
84-
timeToLive.MultiplyBy(ttlWaitMlutiplier),
85-
lru =>
81+
lru.GetOrAdd(1, valueFactory.Create);
82+
return lru;
83+
},
84+
timeToLive.MultiplyBy(ttlWaitMlutiplier),
85+
lru =>
8686
{
8787
lru.TryUpdate(1, "3");
8888
lru.TryGet(1, out var value).Should().BeTrue();
89-
}
90-
);
91-
}
92-
93-
// Using async/await makes this very unstable due to xunit
94-
// running new tests on the yielding thread. Using sleep
95-
// forces the test to stay on the same thread.
96-
[Fact]
97-
public void WhenItemIsReadTtlIsExtended()
98-
{
99-
Timed.Execute(
100-
capacity,
101-
cap =>
89+
}
90+
);
91+
}
92+
93+
// Using async/await makes this very unstable due to xunit
94+
// running new tests on the yielding thread. Using sleep
95+
// forces the test to stay on the same thread.
96+
[Fact]
97+
public void WhenItemIsReadTtlIsExtended()
98+
{
99+
Timed.Execute(
100+
capacity,
101+
cap =>
102102
{
103103
var lru = new ConcurrentLruBuilder<int, string>()
104104
.WithCapacity(cap)
105105
.WithExpireAfterAccess(TimeSpan.FromMilliseconds(100))
106106
.Build();
107107

108-
lru.GetOrAdd(1, valueFactory.Create);
109-
110-
return lru;
111-
},
112-
TimeSpan.FromMilliseconds(50),
113-
lru =>
108+
lru.GetOrAdd(1, valueFactory.Create);
109+
110+
return lru;
111+
},
112+
TimeSpan.FromMilliseconds(50),
113+
lru =>
114114
{
115-
lru.TryGet(1, out _).Should().BeTrue($"First");
116-
},
117-
TimeSpan.FromMilliseconds(75),
118-
lru =>
115+
lru.TryGet(1, out _).Should().BeTrue($"First");
116+
},
117+
TimeSpan.FromMilliseconds(75),
118+
lru =>
119119
{
120-
lru.TryGet(1, out var value).Should().BeTrue($"Second");
121-
}
122-
);
123-
}
124-
125-
[Fact]
126-
public void WhenValueEvictedItemRemovedEventIsFired()
127-
{
128-
var lruEvents = new ConcurrentLruBuilder<int, int>()
129-
.WithCapacity(new EqualCapacityPartition(6))
130-
.WithExpireAfterAccess(TimeSpan.FromSeconds(10))
131-
.WithMetrics()
132-
.Build();
133-
134-
lruEvents.Events.Value.ItemRemoved += OnLruItemRemoved;
135-
136-
// First 6 adds
137-
// hot[6, 5], warm[2, 1], cold[4, 3]
138-
// =>
139-
// hot[8, 7], warm[1, 0], cold[6, 5], evicted[4, 3]
140-
for (int i = 0; i < 8; i++)
141-
{
142-
lruEvents.GetOrAdd(i + 1, i => i + 1);
143-
}
144-
145-
removedItems.Count.Should().Be(2);
146-
147-
removedItems[0].Key.Should().Be(1);
148-
removedItems[0].Value.Should().Be(2);
149-
removedItems[0].Reason.Should().Be(ItemRemovedReason.Evicted);
150-
151-
removedItems[1].Key.Should().Be(4);
152-
removedItems[1].Value.Should().Be(5);
153-
removedItems[1].Reason.Should().Be(ItemRemovedReason.Evicted);
154-
}
155-
156-
[Fact]
157-
public void WhenItemsAreExpiredExpireRemovesExpiredItems()
158-
{
159-
Timed.Execute(
160-
lru,
161-
lru =>
120+
lru.TryGet(1, out var value).Should().BeTrue($"Second");
121+
}
122+
);
123+
}
124+
125+
[Fact]
126+
public void WhenValueEvictedItemRemovedEventIsFired()
127+
{
128+
var lruEvents = new ConcurrentLruBuilder<int, int>()
129+
.WithCapacity(new EqualCapacityPartition(6))
130+
.WithExpireAfterAccess(TimeSpan.FromSeconds(10))
131+
.WithMetrics()
132+
.Build();
133+
134+
lruEvents.Events.Value.ItemRemoved += OnLruItemRemoved;
135+
136+
// First 6 adds
137+
// hot[6, 5], warm[2, 1], cold[4, 3]
138+
// =>
139+
// hot[8, 7], warm[1, 0], cold[6, 5], evicted[4, 3]
140+
for (int i = 0; i < 8; i++)
141+
{
142+
lruEvents.GetOrAdd(i + 1, i => i + 1);
143+
}
144+
145+
removedItems.Count.Should().Be(2);
146+
147+
removedItems[0].Key.Should().Be(1);
148+
removedItems[0].Value.Should().Be(2);
149+
removedItems[0].Reason.Should().Be(ItemRemovedReason.Evicted);
150+
151+
removedItems[1].Key.Should().Be(4);
152+
removedItems[1].Value.Should().Be(5);
153+
removedItems[1].Reason.Should().Be(ItemRemovedReason.Evicted);
154+
}
155+
156+
[Fact]
157+
public void WhenItemsAreExpiredExpireRemovesExpiredItems()
158+
{
159+
Timed.Execute(
160+
lru,
161+
lru =>
162162
{
163163
lru.AddOrUpdate(1, "1");
164164
lru.AddOrUpdate(2, "2");
@@ -175,20 +175,20 @@ public void WhenItemsAreExpiredExpireRemovesExpiredItems()
175175
lru.AddOrUpdate(8, "8");
176176
lru.AddOrUpdate(9, "9");
177177

178-
return lru;
179-
},
180-
timeToLive.MultiplyBy(ttlWaitMlutiplier),
178+
return lru;
179+
},
180+
timeToLive.MultiplyBy(ttlWaitMlutiplier),
181181
lru =>
182182
{
183183
lru.Policy.ExpireAfterAccess.Value.TrimExpired();
184184

185185
lru.Count.Should().Be(0);
186-
}
187-
);
188-
}
189-
190-
[Fact]
191-
public void WhenCacheHasExpiredAndFreshItemsExpireRemovesOnlyExpiredItems()
186+
}
187+
);
188+
}
189+
190+
[Fact]
191+
public void WhenCacheHasExpiredAndFreshItemsExpireRemovesOnlyExpiredItems()
192192
{
193193
Timed.Execute(
194194
lru,
@@ -215,11 +215,11 @@ public void WhenCacheHasExpiredAndFreshItemsExpireRemovesOnlyExpiredItems()
215215

216216
lru.Count.Should().Be(3);
217217
}
218-
);
219-
}
220-
221-
[Fact]
222-
public void WhenItemsAreExpiredTrimRemovesExpiredItems()
218+
);
219+
}
220+
221+
[Fact]
222+
public void WhenItemsAreExpiredTrimRemovesExpiredItems()
223223
{
224224
Timed.Execute(
225225
lru,
@@ -238,7 +238,7 @@ public void WhenItemsAreExpiredTrimRemovesExpiredItems()
238238

239239
lru.Count.Should().Be(0);
240240
}
241-
);
242-
}
243-
}
244-
}
241+
);
242+
}
243+
}
244+
}

BitFaster.Caching/Lru/StopwatchTickConverter.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Diagnostics;
3+
using System.Runtime.CompilerServices;
34

45
namespace BitFaster.Caching.Lru
56
{
@@ -8,6 +9,7 @@ internal static class StopwatchTickConverter
89
// On some platforms (e.g. MacOS), stopwatch and timespan have different resolution
910
private static readonly double stopwatchAdjustmentFactor = Stopwatch.Frequency / (double)TimeSpan.TicksPerSecond;
1011

12+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
1113
internal static long ToTicks(TimeSpan timespan)
1214
{
1315
// mac adjustment factor is 100, giving lowest maximum TTL on mac platform - use same upper limit on all platforms for consistency
@@ -20,6 +22,7 @@ internal static long ToTicks(TimeSpan timespan)
2022
return (long)(timespan.Ticks * stopwatchAdjustmentFactor);
2123
}
2224

25+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2326
internal static TimeSpan FromTicks(long ticks)
2427
{
2528
return TimeSpan.FromTicks((long)(ticks / stopwatchAdjustmentFactor));

0 commit comments

Comments
 (0)