Skip to content

Commit f026ec1

Browse files
authored
memcache hr (#281)
1 parent 45b96d9 commit f026ec1

File tree

4 files changed

+232
-0
lines changed

4 files changed

+232
-0
lines changed

BitFaster.Caching.HitRateAnalysis/Analysis.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,22 @@ public class Analysis<K>
1414
private readonly ConcurrentLru<K, int> concurrentLru;
1515
private readonly ClassicLru<K, int> classicLru;
1616
private readonly ConcurrentLfu<K, int> concurrentLfu;
17+
private readonly MemoryCacheAdaptor<K, int> memoryCache;
1718

1819
public Analysis(int cacheSize)
1920
{
2021
concurrentLru = new ConcurrentLru<K, int>(1, cacheSize, EqualityComparer<K>.Default);
2122
classicLru = new ClassicLru<K, int>(1, cacheSize, EqualityComparer<K>.Default);
2223
concurrentLfu = new ConcurrentLfu<K, int>(1, cacheSize, new ForegroundScheduler(), EqualityComparer<K>.Default);
24+
memoryCache = new MemoryCacheAdaptor<K, int>(cacheSize);
2325
}
2426

2527
public int CacheSize => concurrentLru.Capacity;
2628

2729
public double ClassicLruHitRate => classicLru.Metrics.Value.HitRatio * 100;
2830

31+
public double MemoryCacheHitRate => memoryCache.Metrics.Value.HitRatio * 100;
32+
2933
public double ConcurrentLruHitRate => concurrentLru.Metrics.Value.HitRatio * 100;
3034

3135
public double ConcurrentLfuHitRate => concurrentLfu.Metrics.Value.HitRatio * 100;
@@ -35,6 +39,7 @@ public void TestKey(K key)
3539
concurrentLru.GetOrAdd(key, u => 1);
3640
classicLru.GetOrAdd(key, u => 1);
3741
concurrentLfu.GetOrAdd(key, u => 1);
42+
memoryCache.GetOrAdd(key, u => 1);
3843
}
3944

4045
public static void WriteToFile(string path, IEnumerable<Analysis<K>> results)

BitFaster.Caching.HitRateAnalysis/BitFaster.Caching.HitRateAnalysis.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
<NoWarn>NU1701</NoWarn>
2525
</PackageReference>
2626
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
27+
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
2728
</ItemGroup>
2829

2930
<ItemGroup>
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
using Microsoft.Extensions.Caching.Memory;
8+
9+
namespace BitFaster.Caching.HitRateAnalysis
10+
{
11+
public class MemoryCacheAdaptor<K, V> : ICache<K, V>
12+
{
13+
MemoryCacheOptionsAccessor accessor;
14+
MemoryCache exMemoryCache;
15+
CachePolicy policy;
16+
CacheMetrics metrics;
17+
18+
public MemoryCacheAdaptor(int capacity)
19+
{
20+
accessor = new MemoryCacheOptionsAccessor();
21+
accessor.Value.SizeLimit = capacity;
22+
23+
exMemoryCache = new MemoryCache(accessor);
24+
policy = new CachePolicy(new Optional<IBoundedPolicy>(new BoundedPolicy(capacity)), Optional<ITimePolicy>.None());
25+
metrics = new CacheMetrics();
26+
}
27+
28+
public int Count => throw new NotImplementedException();
29+
30+
public Optional<ICacheMetrics> Metrics => new Optional<ICacheMetrics>(this.metrics);
31+
32+
public Optional<ICacheEvents<K, V>> Events => throw new NotImplementedException();
33+
34+
public CachePolicy Policy => this.policy;
35+
36+
public ICollection<K> Keys => throw new NotImplementedException();
37+
38+
private static readonly MemoryCacheEntryOptions SizeOne = new MemoryCacheEntryOptions() { Size = 1 };
39+
40+
public void AddOrUpdate(K key, V value)
41+
{
42+
exMemoryCache.Set(key, value, SizeOne);
43+
}
44+
45+
public void Clear()
46+
{
47+
throw new NotImplementedException();
48+
}
49+
50+
public IEnumerator<KeyValuePair<K, V>> GetEnumerator()
51+
{
52+
throw new NotImplementedException();
53+
}
54+
55+
public V GetOrAdd(K key, Func<K, V> valueFactory)
56+
{
57+
if (!exMemoryCache.TryGetValue(key, out object result))
58+
{
59+
using ICacheEntry entry = exMemoryCache.CreateEntry(key);
60+
61+
result = valueFactory(key);
62+
entry.Value = result;
63+
entry.SetSize(1);
64+
65+
this.metrics.requestMissCount++;
66+
}
67+
else
68+
{
69+
this.metrics.requestHitCount++;
70+
}
71+
72+
return (V)result;
73+
}
74+
75+
public bool TryGet(K key, out V value)
76+
{
77+
throw new NotImplementedException();
78+
}
79+
80+
public bool TryRemove(K key)
81+
{
82+
throw new NotImplementedException();
83+
}
84+
85+
public bool TryUpdate(K key, V value)
86+
{
87+
throw new NotImplementedException();
88+
}
89+
90+
IEnumerator IEnumerable.GetEnumerator()
91+
{
92+
throw new NotImplementedException();
93+
}
94+
95+
private class BoundedPolicy : IBoundedPolicy
96+
{
97+
private int capacity;
98+
99+
public BoundedPolicy(int capacity)
100+
{
101+
this.capacity = capacity;
102+
}
103+
104+
public int Capacity => this.capacity;
105+
106+
public void Trim(int itemCount)
107+
{
108+
throw new NotImplementedException();
109+
}
110+
}
111+
112+
private class CacheMetrics : ICacheMetrics
113+
{
114+
public long requestHitCount;
115+
public long requestMissCount;
116+
117+
public double HitRatio => (double)requestHitCount / (double)Total;
118+
119+
public long Total => requestHitCount + requestMissCount;
120+
121+
public long Hits => requestHitCount;
122+
123+
public long Misses => requestMissCount;
124+
125+
public long Evicted => throw new NotImplementedException();
126+
127+
public long Updated => throw new NotImplementedException();
128+
}
129+
}
130+
131+
public class MemoryCacheOptionsAccessor
132+
: Microsoft.Extensions.Options.IOptions<MemoryCacheOptions>
133+
{
134+
private readonly MemoryCacheOptions options = new MemoryCacheOptions();
135+
136+
public MemoryCacheOptions Value => this.options;
137+
138+
}
139+
}

BitFaster.Caching.HitRateAnalysis/Zipfian/Runner.cs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Linq;
55
using System.Text;
66
using System.Threading.Tasks;
7+
using BitFaster.Caching.Lfu;
78
using BitFaster.Caching.Lru;
89
using BitFaster.Caching.ThroughputAnalysis;
910
using MathNet.Numerics;
@@ -74,9 +75,13 @@ public static void Run()
7475

7576
var concurrentLru = new ConcurrentLru<int, int>(1, cacheSize, EqualityComparer<int>.Default);
7677
var classicLru = new ClassicLru<int, int>(1, cacheSize, EqualityComparer<int>.Default);
78+
var memCache = new MemoryCacheAdaptor<int, int>(cacheSize);
79+
var concurrentLfu = new ConcurrentLfu<int, int>(cacheSize);
7780

7881
var concurrentLruScan = new ConcurrentLru<int, int>(1, cacheSize, EqualityComparer<int>.Default);
7982
var classicLruScan = new ClassicLru<int, int>(1, cacheSize, EqualityComparer<int>.Default);
83+
var memCacheScan = new MemoryCacheAdaptor<int, int>(cacheSize);
84+
var concurrentLfuScan = new ConcurrentLfu<int, int>(cacheSize);
8085

8186
var d = a.s == 0.5 ? 0 : 1;
8287

@@ -88,6 +93,14 @@ public static void Run()
8893
lruSw.Stop();
8994
Console.WriteLine($"concurrentLru size={cacheSize} took {lruSw.Elapsed}.");
9095

96+
var lfuSw = Stopwatch.StartNew();
97+
for (int i = 0; i < sampleCount; i++)
98+
{
99+
concurrentLfu.GetOrAdd(zipdfDistribution[d][i], func);
100+
}
101+
lfuSw.Stop();
102+
Console.WriteLine($"concurrentLfu size={cacheSize} took {lfuSw.Elapsed}.");
103+
91104
var clruSw = Stopwatch.StartNew();
92105
for (int i = 0; i < sampleCount; i++)
93106
{
@@ -96,6 +109,14 @@ public static void Run()
96109
clruSw.Stop();
97110
Console.WriteLine($"classic lru size={cacheSize} took {clruSw.Elapsed}.");
98111

112+
var memSw = Stopwatch.StartNew();
113+
for (int i = 0; i < sampleCount; i++)
114+
{
115+
memCache.GetOrAdd(zipdfDistribution[d][i], func);
116+
}
117+
memSw.Stop();
118+
Console.WriteLine($"memcache size={cacheSize} took {memSw.Elapsed}.");
119+
99120
var lruSwScan = Stopwatch.StartNew();
100121
for (int i = 0; i < sampleCount; i++)
101122
{
@@ -105,6 +126,15 @@ public static void Run()
105126
lruSwScan.Stop();
106127
Console.WriteLine($"concurrentLruScan lru size={cacheSize} took {lruSwScan.Elapsed}.");
107128

129+
var lfuSwScan = Stopwatch.StartNew();
130+
for (int i = 0; i < sampleCount; i++)
131+
{
132+
concurrentLfuScan.GetOrAdd(zipdfDistribution[d][i], func);
133+
concurrentLfuScan.GetOrAdd(i % n, func);
134+
}
135+
lfuSwScan.Stop();
136+
Console.WriteLine($"concurrentLfuScan lru size={cacheSize} took {lfuSwScan.Elapsed}.");
137+
108138
var clruSwScan = Stopwatch.StartNew();
109139
for (int i = 0; i < sampleCount; i++)
110140
{
@@ -114,6 +144,15 @@ public static void Run()
114144
clruSwScan.Stop();
115145
Console.WriteLine($"classicLruScan lru size={cacheSize} took {clruSwScan.Elapsed}.");
116146

147+
var memSwScan = Stopwatch.StartNew();
148+
for (int i = 0; i < sampleCount; i++)
149+
{
150+
memCacheScan.GetOrAdd(zipdfDistribution[d][i], func);
151+
memCacheScan.GetOrAdd(i % n, func);
152+
}
153+
memSwScan.Stop();
154+
Console.WriteLine($"memcacheScan size={cacheSize} took {memSwScan.Elapsed}.");
155+
117156
results.Add(new AnalysisResult
118157
{
119158
Cache = "ClassicLru",
@@ -126,6 +165,18 @@ public static void Run()
126165
Duration = clruSw.Elapsed,
127166
});
128167

168+
results.Add(new AnalysisResult
169+
{
170+
Cache = "MemoryCache",
171+
N = a.N,
172+
s = a.s,
173+
CacheSizePercent = a.CacheSizePercent * 100.0,
174+
Samples = a.Samples,
175+
IsScan = false,
176+
HitRatio = memCache.Metrics.Value.HitRatio * 100.0,
177+
Duration = memSw.Elapsed,
178+
});
179+
129180
results.Add(new AnalysisResult
130181
{
131182
Cache = "ConcurrentLru",
@@ -138,6 +189,18 @@ public static void Run()
138189
Duration = lruSw.Elapsed,
139190
});
140191

192+
results.Add(new AnalysisResult
193+
{
194+
Cache = "ConcurrentLfu",
195+
N = a.N,
196+
s = a.s,
197+
CacheSizePercent = a.CacheSizePercent * 100.0,
198+
Samples = a.Samples,
199+
IsScan = false,
200+
HitRatio = concurrentLfu.Metrics.Value.HitRatio * 100.0,
201+
Duration = lfuSw.Elapsed,
202+
});
203+
141204
results.Add(new AnalysisResult
142205
{
143206
Cache = "ClassicLru",
@@ -150,6 +213,18 @@ public static void Run()
150213
Duration = clruSwScan.Elapsed,
151214
});
152215

216+
results.Add(new AnalysisResult
217+
{
218+
Cache = "MemoryCache",
219+
N = a.N,
220+
s = a.s,
221+
CacheSizePercent = a.CacheSizePercent * 100.0,
222+
Samples = a.Samples,
223+
IsScan = true,
224+
HitRatio = memCacheScan.Metrics.Value.HitRatio * 100.0,
225+
Duration = memSwScan.Elapsed,
226+
});
227+
153228
results.Add(new AnalysisResult
154229
{
155230
Cache = "ConcurrentLru",
@@ -161,6 +236,18 @@ public static void Run()
161236
HitRatio = concurrentLruScan.Metrics.Value.HitRatio * 100.0,
162237
Duration = lruSwScan.Elapsed,
163238
});
239+
240+
results.Add(new AnalysisResult
241+
{
242+
Cache = "ConcurrentLfu",
243+
N = a.N,
244+
s = a.s,
245+
CacheSizePercent = a.CacheSizePercent * 100.0,
246+
Samples = a.Samples,
247+
IsScan = true,
248+
HitRatio = concurrentLfuScan.Metrics.Value.HitRatio * 100.0,
249+
Duration = lfuSwScan.Elapsed,
250+
});
164251
}
165252

166253
results.WriteToConsole();

0 commit comments

Comments
 (0)