mirror of https://github.com/ppy/osu
Add statistics display for `MemoryCachingComponent`s
Never sure if these are working as they should (or how well they are working). This helps quite a bit.
This commit is contained in:
parent
7053a8507b
commit
a1b6ec60c8
|
@ -8,7 +8,9 @@
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using osu.Framework.Extensions.TypeExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Statistics;
|
||||||
|
|
||||||
namespace osu.Game.Database
|
namespace osu.Game.Database
|
||||||
{
|
{
|
||||||
|
@ -20,8 +22,16 @@ public abstract class MemoryCachingComponent<TLookup, TValue> : Component
|
||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<TLookup, TValue> cache = new ConcurrentDictionary<TLookup, TValue>();
|
private readonly ConcurrentDictionary<TLookup, TValue> cache = new ConcurrentDictionary<TLookup, TValue>();
|
||||||
|
|
||||||
|
private readonly GlobalStatistic<MemoryCachingStatistics> statistics;
|
||||||
|
|
||||||
protected virtual bool CacheNullValues => true;
|
protected virtual bool CacheNullValues => true;
|
||||||
|
|
||||||
|
protected MemoryCachingComponent()
|
||||||
|
{
|
||||||
|
statistics = GlobalStatistics.Get<MemoryCachingStatistics>(nameof(MemoryCachingComponent<TLookup, TValue>), GetType().ReadableName());
|
||||||
|
statistics.Value = new MemoryCachingStatistics();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieve the cached value for the given lookup.
|
/// Retrieve the cached value for the given lookup.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -30,12 +40,20 @@ public abstract class MemoryCachingComponent<TLookup, TValue> : Component
|
||||||
protected async Task<TValue> GetAsync([NotNull] TLookup lookup, CancellationToken token = default)
|
protected async Task<TValue> GetAsync([NotNull] TLookup lookup, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
if (CheckExists(lookup, out TValue performance))
|
if (CheckExists(lookup, out TValue performance))
|
||||||
|
{
|
||||||
|
statistics.Value.HitCount++;
|
||||||
return performance;
|
return performance;
|
||||||
|
}
|
||||||
|
|
||||||
var computed = await ComputeValueAsync(lookup, token).ConfigureAwait(false);
|
var computed = await ComputeValueAsync(lookup, token).ConfigureAwait(false);
|
||||||
|
|
||||||
|
statistics.Value.MissCount++;
|
||||||
|
|
||||||
if (computed != null || CacheNullValues)
|
if (computed != null || CacheNullValues)
|
||||||
|
{
|
||||||
cache[lookup] = computed;
|
cache[lookup] = computed;
|
||||||
|
statistics.Value.Usage = cache.Count;
|
||||||
|
}
|
||||||
|
|
||||||
return computed;
|
return computed;
|
||||||
}
|
}
|
||||||
|
@ -51,6 +69,8 @@ protected void Invalidate(Func<TLookup, bool> matchKeyPredicate)
|
||||||
if (matchKeyPredicate(kvp.Key))
|
if (matchKeyPredicate(kvp.Key))
|
||||||
cache.TryRemove(kvp.Key, out _);
|
cache.TryRemove(kvp.Key, out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statistics.Value.Usage = cache.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool CheckExists([NotNull] TLookup lookup, out TValue value) =>
|
protected bool CheckExists([NotNull] TLookup lookup, out TValue value) =>
|
||||||
|
@ -63,5 +83,31 @@ protected bool CheckExists([NotNull] TLookup lookup, out TValue value) =>
|
||||||
/// <param name="token">An optional <see cref="CancellationToken"/> to cancel the operation.</param>
|
/// <param name="token">An optional <see cref="CancellationToken"/> to cancel the operation.</param>
|
||||||
/// <returns>The computed value.</returns>
|
/// <returns>The computed value.</returns>
|
||||||
protected abstract Task<TValue> ComputeValueAsync(TLookup lookup, CancellationToken token = default);
|
protected abstract Task<TValue> ComputeValueAsync(TLookup lookup, CancellationToken token = default);
|
||||||
|
|
||||||
|
private class MemoryCachingStatistics
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Total number of cache hits.
|
||||||
|
/// </summary>
|
||||||
|
public int HitCount;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total number of cache misses.
|
||||||
|
/// </summary>
|
||||||
|
public int MissCount;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total number of cached entities.
|
||||||
|
/// </summary>
|
||||||
|
public int Usage;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
int totalAccesses = HitCount + MissCount;
|
||||||
|
double hitRate = totalAccesses == 0 ? 0 : (double)HitCount / totalAccesses;
|
||||||
|
|
||||||
|
return $"i:{Usage} h:{HitCount} m:{MissCount} {hitRate:0%}";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue