Fix and simplify TranslatorCache
This commit is contained in:
parent
ad00fd0244
commit
3a8165f421
1 changed files with 30 additions and 71 deletions
|
@ -1,7 +1,7 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
|
@ -15,71 +15,49 @@ namespace ChocolArm64
|
||||||
//Minimum time required in milliseconds for a method to be eligible for deletion.
|
//Minimum time required in milliseconds for a method to be eligible for deletion.
|
||||||
private const int MinTimeDelta = 2 * 60000;
|
private const int MinTimeDelta = 2 * 60000;
|
||||||
|
|
||||||
//Minimum number of calls required to update the timestamp.
|
|
||||||
private const int MinCallCountForUpdate = 250;
|
|
||||||
|
|
||||||
private class CacheBucket
|
private class CacheBucket
|
||||||
{
|
{
|
||||||
public TranslatedSub Subroutine { get; private set; }
|
public TranslatedSub Subroutine { get; private set; }
|
||||||
|
|
||||||
public LinkedListNode<long> Node { get; private set; }
|
|
||||||
|
|
||||||
public int CallCount { get; set; }
|
|
||||||
|
|
||||||
public int Size { get; private set; }
|
public int Size { get; private set; }
|
||||||
|
|
||||||
public long Timestamp { get; private set; }
|
public long Timestamp { get; private set; }
|
||||||
|
|
||||||
public CacheBucket(TranslatedSub subroutine, LinkedListNode<long> node, int size)
|
public CacheBucket(TranslatedSub subroutine, int size)
|
||||||
{
|
{
|
||||||
Subroutine = subroutine;
|
Subroutine = subroutine;
|
||||||
Size = size;
|
Size = size;
|
||||||
|
|
||||||
UpdateNode(node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateNode(LinkedListNode<long> node)
|
public void UpdateTimestamp()
|
||||||
{
|
{
|
||||||
Node = node;
|
|
||||||
|
|
||||||
Timestamp = GetTimestamp();
|
Timestamp = GetTimestamp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConcurrentDictionary<long, CacheBucket> _cache;
|
private ConcurrentDictionary<long, CacheBucket> _cache;
|
||||||
|
|
||||||
private LinkedList<long> _sortedCache;
|
|
||||||
|
|
||||||
private int _totalSize;
|
private int _totalSize;
|
||||||
|
|
||||||
public TranslatorCache()
|
public TranslatorCache()
|
||||||
{
|
{
|
||||||
_cache = new ConcurrentDictionary<long, CacheBucket>();
|
_cache = new ConcurrentDictionary<long, CacheBucket>();
|
||||||
|
|
||||||
_sortedCache = new LinkedList<long>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddOrUpdate(long position, TranslatedSub subroutine, int size)
|
public void AddOrUpdate(long position, TranslatedSub subroutine, int size)
|
||||||
{
|
{
|
||||||
ClearCacheIfNeeded();
|
ClearCacheIfNeeded();
|
||||||
|
|
||||||
_totalSize += size;
|
CacheBucket newBucket = new CacheBucket(subroutine, size);
|
||||||
|
|
||||||
lock (_sortedCache)
|
_cache.AddOrUpdate(position, newBucket, (key, oldBucket) =>
|
||||||
{
|
{
|
||||||
LinkedListNode<long> node = _sortedCache.AddLast(position);
|
Interlocked.Add(ref _totalSize, -oldBucket.Size);
|
||||||
|
|
||||||
CacheBucket newBucket = new CacheBucket(subroutine, node, size);
|
|
||||||
|
|
||||||
_cache.AddOrUpdate(position, newBucket, (key, bucket) =>
|
|
||||||
{
|
|
||||||
_totalSize -= bucket.Size;
|
|
||||||
|
|
||||||
_sortedCache.Remove(bucket.Node);
|
|
||||||
|
|
||||||
return newBucket;
|
return newBucket;
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
Interlocked.Add(ref _totalSize, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasSubroutine(long position)
|
public bool HasSubroutine(long position)
|
||||||
|
@ -92,24 +70,7 @@ namespace ChocolArm64
|
||||||
{
|
{
|
||||||
if (_cache.TryGetValue(position, out CacheBucket bucket))
|
if (_cache.TryGetValue(position, out CacheBucket bucket))
|
||||||
{
|
{
|
||||||
if (bucket.CallCount++ > MinCallCountForUpdate)
|
bucket.UpdateTimestamp();
|
||||||
{
|
|
||||||
if (Monitor.TryEnter(_sortedCache))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
bucket.CallCount = 0;
|
|
||||||
|
|
||||||
_sortedCache.Remove(bucket.Node);
|
|
||||||
|
|
||||||
bucket.UpdateNode(_sortedCache.AddLast(position));
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
Monitor.Exit(_sortedCache);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
subroutine = bucket.Subroutine;
|
subroutine = bucket.Subroutine;
|
||||||
|
|
||||||
|
@ -123,20 +84,16 @@ namespace ChocolArm64
|
||||||
|
|
||||||
private void ClearCacheIfNeeded()
|
private void ClearCacheIfNeeded()
|
||||||
{
|
{
|
||||||
long timestamp = GetTimestamp();
|
if (_totalSize <= MaxTotalSize)
|
||||||
|
|
||||||
while (_totalSize > MaxTotalSize)
|
|
||||||
{
|
{
|
||||||
lock (_sortedCache)
|
return;
|
||||||
{
|
|
||||||
LinkedListNode<long> node = _sortedCache.First;
|
|
||||||
|
|
||||||
if (node == null)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CacheBucket bucket = _cache[node.Value];
|
long timestamp = GetTimestamp();
|
||||||
|
|
||||||
|
foreach (KeyValuePair<long, CacheBucket> kv in _cache.OrderBy(x => (ulong)x.Value.Timestamp))
|
||||||
|
{
|
||||||
|
CacheBucket bucket = kv.Value;
|
||||||
|
|
||||||
long timeDelta = timestamp - bucket.Timestamp;
|
long timeDelta = timestamp - bucket.Timestamp;
|
||||||
|
|
||||||
|
@ -145,12 +102,14 @@ namespace ChocolArm64
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_cache.TryRemove(node.Value, out bucket))
|
if (_cache.Remove(kv.Key, out bucket))
|
||||||
{
|
{
|
||||||
_totalSize -= bucket.Size;
|
Interlocked.Add(ref _totalSize, -bucket.Size);
|
||||||
|
|
||||||
_sortedCache.Remove(bucket.Node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_totalSize <= MaxTotalSize)
|
||||||
|
{
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue