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
4 changes: 2 additions & 2 deletions BitFaster.Caching.HitRateAnalysis/Arc/Analysis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ public Analysis(int cacheSize)

public int CacheSize => concurrentLru.Capacity;

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

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

public void TestKey(long key)
{
Expand Down
4 changes: 2 additions & 2 deletions BitFaster.Caching.HitRateAnalysis/Glimpse/Analysis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ public Analysis(int cacheSize)

public int CacheSize => this.concurrentLru.Capacity;

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

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

public void TestKey(long key)
{
Expand Down
4 changes: 2 additions & 2 deletions BitFaster.Caching.HitRateAnalysis/Wikibench/Analysis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ public Analysis(int cacheSize)

public int CacheSize => this.concurrentLru.Capacity;

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

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

public void TestUri(Uri uri)
{
Expand Down
6 changes: 3 additions & 3 deletions BitFaster.Caching.HitRateAnalysis/Zipfian/Runner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public static void Run()
CacheSizePercent = a.CacheSizePercent * 100.0,
Samples = a.Samples,
IsScan = false,
HitRatio = concurrentLru.HitRatio * 100.0,
HitRatio = concurrentLru.Metrics.HitRatio * 100.0,
Duration = lruSw.Elapsed,
});

Expand All @@ -146,7 +146,7 @@ public static void Run()
CacheSizePercent = a.CacheSizePercent * 100.0,
Samples = a.Samples,
IsScan = true,
HitRatio = classicLruScan.HitRatio * 100.0,
HitRatio = classicLruScan.Metrics.HitRatio * 100.0,
Duration = clruSwScan.Elapsed,
});

Expand All @@ -158,7 +158,7 @@ public static void Run()
CacheSizePercent = a.CacheSizePercent * 100.0,
Samples = a.Samples,
IsScan = true,
HitRatio = concurrentLruScan.HitRatio * 100.0,
HitRatio = concurrentLruScan.Metrics.HitRatio * 100.0,
Duration = lruSwScan.Elapsed,
});
}
Expand Down
44 changes: 44 additions & 0 deletions BitFaster.Caching.UnitTests/Lru/ClassicLruTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,51 @@ public void WhenItemIsAddedThenRetrievedHitRatioIsHalf()
lru.GetOrAdd(1, valueFactory.Create);
bool result = lru.TryGet(1, out var value);

#pragma warning disable CS0618 // Type or member is obsolete
lru.HitRatio.Should().Be(0.5);
#pragma warning restore CS0618 // Type or member is obsolete
}

[Fact]
public void MetricsAreEnabled()
{
lru.Metrics.IsEnabled.Should().BeTrue();
}

[Fact]
public void WhenItemIsAddedThenRetrievedMetricHitRatioIsHalf()
{
lru.GetOrAdd(1, valueFactory.Create);
bool result = lru.TryGet(1, out var value);

lru.Metrics.HitRatio.Should().Be(0.5);
}

[Fact]
public void WhenItemIsAddedThenRetrievedMetricHitsIs1()
{
lru.GetOrAdd(1, valueFactory.Create);
bool result = lru.TryGet(1, out var value);

lru.Metrics.Hits.Should().Be(1);
}

[Fact]
public void WhenItemIsAddedThenRetrievedMetricTotalIs2()
{
lru.GetOrAdd(1, valueFactory.Create);
bool result = lru.TryGet(1, out var value);

lru.Metrics.Total.Should().Be(2);
}

[Fact]
public void WhenItemDoesNotExistTryGetIncrementsMiss()
{
lru.GetOrAdd(1, valueFactory.Create);
bool result = lru.TryGet(1, out var value);

lru.Metrics.Misses.Should().Be(1);
}

[Fact]
Expand Down
11 changes: 11 additions & 0 deletions BitFaster.Caching.UnitTests/Lru/ConcurrentLruTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,18 @@ public void WhenItemIsAddedThenRetrievedHitRatioIsHalf()
lru.GetOrAdd(1, valueFactory.Create);
bool result = lru.TryGet(1, out var value);

#pragma warning disable CS0618 // Type or member is obsolete
lru.HitRatio.Should().Be(0.5);
#pragma warning restore CS0618 // Type or member is obsolete
}

[Fact]
public void WhenItemIsAddedThenRetrievedMetricHitRatioIsHalf()
{
lru.GetOrAdd(1, valueFactory.Create);
bool result = lru.TryGet(1, out var value);

lru.Metrics.HitRatio.Should().Be(0.5);
}

[Fact]
Expand Down
2 changes: 2 additions & 0 deletions BitFaster.Caching.UnitTests/Lru/ConcurrentTLruTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,9 @@ public void WhenItemIsAddedThenRetrievedHitRatioIsHalf()
lru.GetOrAdd(1, valueFactory.Create);
bool result = lru.TryGet(1, out var value);

#pragma warning disable CS0618 // Type or member is obsolete
lru.HitRatio.Should().Be(0.5);
#pragma warning restore CS0618 // Type or member is obsolete
}

[Fact]
Expand Down
24 changes: 24 additions & 0 deletions BitFaster.Caching.UnitTests/Lru/NoTelemetryPolicyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,30 @@ public void HitRatioIsZero()
counter.HitRatio.Should().Be(0);
}

[Fact]
public void TotalIsZero()
{
counter.Total.Should().Be(0);
}

[Fact]
public void HitsIsZero()
{
counter.Hits.Should().Be(0);
}

[Fact]
public void MissesIsZero()
{
counter.Misses.Should().Be(0);
}

[Fact]
public void IsEnabledIsFalse()
{
counter.IsEnabled.Should().BeFalse();
}

[Fact]
public void IncrementHitCountIsNoOp()
{
Expand Down
30 changes: 30 additions & 0 deletions BitFaster.Caching.UnitTests/Lru/TelemetryPolicyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,36 @@ public class TelemetryPolicyTests
{
private TelemetryPolicy<int, int> telemetryPolicy = default;

[Fact]
public void WhenHitTotalIs1()
{
telemetryPolicy.Total.Should().Be(0);
telemetryPolicy.IncrementHit();
telemetryPolicy.Total.Should().Be(1);
}

[Fact]
public void WhenHitHitsIs1()
{
telemetryPolicy.Hits.Should().Be(0);
telemetryPolicy.IncrementHit();
telemetryPolicy.Hits.Should().Be(1);
}

[Fact]
public void WhenMissMissesIs1()
{
telemetryPolicy.Misses.Should().Be(0);
telemetryPolicy.IncrementMiss();
telemetryPolicy.Misses.Should().Be(1);
}

[Fact]
public void IsEnabledIsTrue()
{
telemetryPolicy.IsEnabled.Should().BeTrue();
}

[Fact]
public void WhenHitCountAndTotalCountAreEqualRatioIs1()
{
Expand Down
10 changes: 10 additions & 0 deletions BitFaster.Caching.UnitTests/ScopedCacheTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ public void WhenItemIsAddedCountIsCorrect()
this.cache.Count.Should().Be(1);
}

[Fact]
public void WhenItemIsAddedThenLookedUpMetricsAreCorrect()
{
this.cache.AddOrUpdate(1, new Disposable());
this.cache.ScopedGetOrAdd(1, k => new Scoped<Disposable>(new Disposable()));

this.cache.Metrics.Misses.Should().Be(0);
this.cache.Metrics.Hits.Should().Be(1);
}

[Fact]
public void WhenKeyDoesNotExistAddOrUpdateAddsNewItem()
{
Expand Down
5 changes: 5 additions & 0 deletions BitFaster.Caching/ICache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public interface ICache<K, V>
/// </summary>
int Count { get; }

/// <summary>
/// Gets the cache metrics.
/// </summary>
ICacheMetrics Metrics { get; }

/// <summary>
/// Attempts to get the value associated with the specified key from the cache.
/// </summary>
Expand Down
41 changes: 41 additions & 0 deletions BitFaster.Caching/ICacheMetrics.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BitFaster.Caching
{
/// <summary>
/// Represents cache metrics collected over the lifetime of the cache.
/// If metrics are disabled, the IsEnabled property returns false
/// and all other properties return zero.
/// </summary>
public interface ICacheMetrics
{
/// <summary>
/// Gets the ratio of hits to misses, where a value of 1 indicates 100% hits.
/// </summary>
double HitRatio { get; }

/// <summary>
/// Gets the total number of requests made to the cache.
/// </summary>
long Total { get; }

/// <summary>
/// Gets the total number of cache hits.
/// </summary>
long Hits { get; }

/// <summary>
/// Gets the total number of cache misses.
/// </summary>
long Misses { get; }

/// <summary>
/// Gets a value indicating whether metrics are enabled.
/// </summary>
bool IsEnabled { get; }
}
}
5 changes: 5 additions & 0 deletions BitFaster.Caching/IScopedCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public interface IScopedCache<K, V> where V : IDisposable
/// </summary>
int Count { get; }

/// <summary>
/// Gets the cache metrics.
/// </summary>
ICacheMetrics Metrics { get; }

/// <summary>
/// Attempts to create a lifetime for the value associated with the specified key from the cache
/// </summary>
Expand Down
29 changes: 24 additions & 5 deletions BitFaster.Caching/Lru/ClassicLru.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ public sealed class ClassicLru<K, V> : ICache<K, V>, IEnumerable<KeyValuePair<K,
private readonly ConcurrentDictionary<K, LinkedListNode<LruItem>> dictionary;
private readonly LinkedList<LruItem> linkedList = new LinkedList<LruItem>();

private long requestHitCount;
private long requestTotalCount;
private readonly CacheMetrics metrics = new CacheMetrics();

public ClassicLru(int capacity)
: this(Defaults.ConcurrencyLevel, capacity, EqualityComparer<K>.Default)
Expand Down Expand Up @@ -57,7 +56,11 @@ public ClassicLru(int concurrencyLevel, int capacity, IEqualityComparer<K> compa
/// <summary>
/// Gets the ratio of hits to misses, where a value of 1 indicates 100% hits.
/// </summary>
public double HitRatio => (double)requestHitCount / (double)requestTotalCount;
[ObsoleteAttribute("This property is obsolete. Use Metrics instead.", false)]
public double HitRatio => this.Metrics.HitRatio;

///<inheritdoc/>
public ICacheMetrics Metrics => this.metrics;

/// <summary>
/// Gets a collection containing the keys in the cache.
Expand All @@ -83,12 +86,12 @@ public IEnumerator<KeyValuePair<K, V>> GetEnumerator()
///<inheritdoc/>
public bool TryGet(K key, out V value)
{
Interlocked.Increment(ref requestTotalCount);
Interlocked.Increment(ref this.metrics.requestTotalCount);

if (dictionary.TryGetValue(key, out var node))
{
LockAndMoveToEnd(node);
Interlocked.Increment(ref requestHitCount);
Interlocked.Increment(ref this.metrics.requestHitCount);
value = node.Value.Value;
return true;
}
Expand Down Expand Up @@ -366,5 +369,21 @@ public LruItem(K k, V v)

public V Value { get; set; }
}

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

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

public long Total => requestTotalCount;

public long Hits => requestHitCount;

public long Misses => requestTotalCount - requestHitCount;

public bool IsEnabled => true;
}
}
}
1 change: 1 addition & 0 deletions BitFaster.Caching/Lru/ConcurrentLru.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public ConcurrentLru(int concurrencyLevel, ICapacityPartition capacity, IEqualit
/// <summary>
/// Gets the ratio of hits to misses, where a value of 1 indicates 100% hits.
/// </summary>
[ObsoleteAttribute("This property is obsolete. Use Metrics instead.", false)]
public double HitRatio => this.telemetryPolicy.HitRatio;

/// <summary>
Expand Down
1 change: 1 addition & 0 deletions BitFaster.Caching/Lru/ConcurrentTLru.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public ConcurrentTLru(int concurrencyLevel, ICapacityPartition capacity, IEquali
/// <summary>
/// Gets the ratio of hits to misses, where a value of 1 indicates 100% hits.
/// </summary>
[ObsoleteAttribute("This property is obsolete. Use Metrics instead.", false)]
public double HitRatio => this.telemetryPolicy.HitRatio;

/// <summary>
Expand Down
4 changes: 1 addition & 3 deletions BitFaster.Caching/Lru/ITelemetryPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,14 @@

namespace BitFaster.Caching.Lru
{
public interface ITelemetryPolicy<K, V>
public interface ITelemetryPolicy<K, V> : ICacheMetrics
{
void IncrementMiss();

void IncrementHit();

void OnItemRemoved(K key, V value, ItemRemovedReason reason);

double HitRatio { get; }

void SetEventSource(object source);
}
}
Loading