Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions BitFaster.Caching.HitRateAnalysis/Analysis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,22 @@ public class Analysis<K>
private readonly ConcurrentLru<K, int> concurrentLru;
private readonly ClassicLru<K, int> classicLru;
private readonly ConcurrentLfu<K, int> concurrentLfu;
private readonly MemoryCacheAdaptor<K, int> memoryCache;

public Analysis(int cacheSize)
{
concurrentLru = new ConcurrentLru<K, int>(1, cacheSize, EqualityComparer<K>.Default);
classicLru = new ClassicLru<K, int>(1, cacheSize, EqualityComparer<K>.Default);
concurrentLfu = new ConcurrentLfu<K, int>(1, cacheSize, new ForegroundScheduler(), EqualityComparer<K>.Default);
memoryCache = new MemoryCacheAdaptor<K, int>(cacheSize);
}

public int CacheSize => concurrentLru.Capacity;

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

public double MemoryCacheHitRate => memoryCache.Metrics.Value.HitRatio * 100;

public double ConcurrentLruHitRate => concurrentLru.Metrics.Value.HitRatio * 100;

public double ConcurrentLfuHitRate => concurrentLfu.Metrics.Value.HitRatio * 100;
Expand All @@ -35,6 +39,7 @@ public void TestKey(K key)
concurrentLru.GetOrAdd(key, u => 1);
classicLru.GetOrAdd(key, u => 1);
concurrentLfu.GetOrAdd(key, u => 1);
memoryCache.GetOrAdd(key, u => 1);
}

public static void WriteToFile(string path, IEnumerable<Analysis<K>> results)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<NoWarn>NU1701</NoWarn>
</PackageReference>
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
</ItemGroup>

<ItemGroup>
Expand Down
139 changes: 139 additions & 0 deletions BitFaster.Caching.HitRateAnalysis/MemoryCacheAdaptor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;

namespace BitFaster.Caching.HitRateAnalysis
{
public class MemoryCacheAdaptor<K, V> : ICache<K, V>
{
MemoryCacheOptionsAccessor accessor;
MemoryCache exMemoryCache;
CachePolicy policy;
CacheMetrics metrics;

public MemoryCacheAdaptor(int capacity)
{
accessor = new MemoryCacheOptionsAccessor();
accessor.Value.SizeLimit = capacity;

exMemoryCache = new MemoryCache(accessor);
policy = new CachePolicy(new Optional<IBoundedPolicy>(new BoundedPolicy(capacity)), Optional<ITimePolicy>.None());
metrics = new CacheMetrics();
}

public int Count => throw new NotImplementedException();

public Optional<ICacheMetrics> Metrics => new Optional<ICacheMetrics>(this.metrics);

public Optional<ICacheEvents<K, V>> Events => throw new NotImplementedException();

public CachePolicy Policy => this.policy;

public ICollection<K> Keys => throw new NotImplementedException();

private static readonly MemoryCacheEntryOptions SizeOne = new MemoryCacheEntryOptions() { Size = 1 };

public void AddOrUpdate(K key, V value)
{
exMemoryCache.Set(key, value, SizeOne);
}

public void Clear()
{
throw new NotImplementedException();
}

public IEnumerator<KeyValuePair<K, V>> GetEnumerator()
{
throw new NotImplementedException();
}

public V GetOrAdd(K key, Func<K, V> valueFactory)
{
if (!exMemoryCache.TryGetValue(key, out object result))
{
using ICacheEntry entry = exMemoryCache.CreateEntry(key);

result = valueFactory(key);
entry.Value = result;
entry.SetSize(1);

this.metrics.requestMissCount++;
}
else
{
this.metrics.requestHitCount++;
}

return (V)result;
}

public bool TryGet(K key, out V value)
{
throw new NotImplementedException();
}

public bool TryRemove(K key)
{
throw new NotImplementedException();
}

public bool TryUpdate(K key, V value)
{
throw new NotImplementedException();
}

IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}

private class BoundedPolicy : IBoundedPolicy
{
private int capacity;

public BoundedPolicy(int capacity)
{
this.capacity = capacity;
}

public int Capacity => this.capacity;

public void Trim(int itemCount)
{
throw new NotImplementedException();
}
}

private class CacheMetrics : ICacheMetrics
{
public long requestHitCount;
public long requestMissCount;

public double HitRatio => (double)requestHitCount / (double)Total;

public long Total => requestHitCount + requestMissCount;

public long Hits => requestHitCount;

public long Misses => requestMissCount;

public long Evicted => throw new NotImplementedException();

public long Updated => throw new NotImplementedException();
}
}

public class MemoryCacheOptionsAccessor
: Microsoft.Extensions.Options.IOptions<MemoryCacheOptions>
{
private readonly MemoryCacheOptions options = new MemoryCacheOptions();

public MemoryCacheOptions Value => this.options;

}
}
87 changes: 87 additions & 0 deletions BitFaster.Caching.HitRateAnalysis/Zipfian/Runner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BitFaster.Caching.Lfu;
using BitFaster.Caching.Lru;
using BitFaster.Caching.ThroughputAnalysis;
using MathNet.Numerics;
Expand Down Expand Up @@ -74,9 +75,13 @@ public static void Run()

var concurrentLru = new ConcurrentLru<int, int>(1, cacheSize, EqualityComparer<int>.Default);
var classicLru = new ClassicLru<int, int>(1, cacheSize, EqualityComparer<int>.Default);
var memCache = new MemoryCacheAdaptor<int, int>(cacheSize);
var concurrentLfu = new ConcurrentLfu<int, int>(cacheSize);

var concurrentLruScan = new ConcurrentLru<int, int>(1, cacheSize, EqualityComparer<int>.Default);
var classicLruScan = new ClassicLru<int, int>(1, cacheSize, EqualityComparer<int>.Default);
var memCacheScan = new MemoryCacheAdaptor<int, int>(cacheSize);
var concurrentLfuScan = new ConcurrentLfu<int, int>(cacheSize);

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

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

var lfuSw = Stopwatch.StartNew();
for (int i = 0; i < sampleCount; i++)
{
concurrentLfu.GetOrAdd(zipdfDistribution[d][i], func);
}
lfuSw.Stop();
Console.WriteLine($"concurrentLfu size={cacheSize} took {lfuSw.Elapsed}.");

var clruSw = Stopwatch.StartNew();
for (int i = 0; i < sampleCount; i++)
{
Expand All @@ -96,6 +109,14 @@ public static void Run()
clruSw.Stop();
Console.WriteLine($"classic lru size={cacheSize} took {clruSw.Elapsed}.");

var memSw = Stopwatch.StartNew();
for (int i = 0; i < sampleCount; i++)
{
memCache.GetOrAdd(zipdfDistribution[d][i], func);
}
memSw.Stop();
Console.WriteLine($"memcache size={cacheSize} took {memSw.Elapsed}.");

var lruSwScan = Stopwatch.StartNew();
for (int i = 0; i < sampleCount; i++)
{
Expand All @@ -105,6 +126,15 @@ public static void Run()
lruSwScan.Stop();
Console.WriteLine($"concurrentLruScan lru size={cacheSize} took {lruSwScan.Elapsed}.");

var lfuSwScan = Stopwatch.StartNew();
for (int i = 0; i < sampleCount; i++)
{
concurrentLfuScan.GetOrAdd(zipdfDistribution[d][i], func);
concurrentLfuScan.GetOrAdd(i % n, func);
}
lfuSwScan.Stop();
Console.WriteLine($"concurrentLfuScan lru size={cacheSize} took {lfuSwScan.Elapsed}.");

var clruSwScan = Stopwatch.StartNew();
for (int i = 0; i < sampleCount; i++)
{
Expand All @@ -114,6 +144,15 @@ public static void Run()
clruSwScan.Stop();
Console.WriteLine($"classicLruScan lru size={cacheSize} took {clruSwScan.Elapsed}.");

var memSwScan = Stopwatch.StartNew();
for (int i = 0; i < sampleCount; i++)
{
memCacheScan.GetOrAdd(zipdfDistribution[d][i], func);
memCacheScan.GetOrAdd(i % n, func);
}
memSwScan.Stop();
Console.WriteLine($"memcacheScan size={cacheSize} took {memSwScan.Elapsed}.");

results.Add(new AnalysisResult
{
Cache = "ClassicLru",
Expand All @@ -126,6 +165,18 @@ public static void Run()
Duration = clruSw.Elapsed,
});

results.Add(new AnalysisResult
{
Cache = "MemoryCache",
N = a.N,
s = a.s,
CacheSizePercent = a.CacheSizePercent * 100.0,
Samples = a.Samples,
IsScan = false,
HitRatio = memCache.Metrics.Value.HitRatio * 100.0,
Duration = memSw.Elapsed,
});

results.Add(new AnalysisResult
{
Cache = "ConcurrentLru",
Expand All @@ -138,6 +189,18 @@ public static void Run()
Duration = lruSw.Elapsed,
});

results.Add(new AnalysisResult
{
Cache = "ConcurrentLfu",
N = a.N,
s = a.s,
CacheSizePercent = a.CacheSizePercent * 100.0,
Samples = a.Samples,
IsScan = false,
HitRatio = concurrentLfu.Metrics.Value.HitRatio * 100.0,
Duration = lfuSw.Elapsed,
});

results.Add(new AnalysisResult
{
Cache = "ClassicLru",
Expand All @@ -150,6 +213,18 @@ public static void Run()
Duration = clruSwScan.Elapsed,
});

results.Add(new AnalysisResult
{
Cache = "MemoryCache",
N = a.N,
s = a.s,
CacheSizePercent = a.CacheSizePercent * 100.0,
Samples = a.Samples,
IsScan = true,
HitRatio = memCacheScan.Metrics.Value.HitRatio * 100.0,
Duration = memSwScan.Elapsed,
});

results.Add(new AnalysisResult
{
Cache = "ConcurrentLru",
Expand All @@ -161,6 +236,18 @@ public static void Run()
HitRatio = concurrentLruScan.Metrics.Value.HitRatio * 100.0,
Duration = lruSwScan.Elapsed,
});

results.Add(new AnalysisResult
{
Cache = "ConcurrentLfu",
N = a.N,
s = a.s,
CacheSizePercent = a.CacheSizePercent * 100.0,
Samples = a.Samples,
IsScan = true,
HitRatio = concurrentLfuScan.Metrics.Value.HitRatio * 100.0,
Duration = lfuSwScan.Elapsed,
});
}

results.WriteToConsole();
Expand Down