From 9cb57fb4bb3bbae0ae052a5af4a96a49fc5d864d Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Tue, 30 Oct 2018 19:43:02 -0600 Subject: Adjust naming conventions for Ryujinx and ChocolArm64 projects (#484) * Change naming convention for Ryujinx project * Change naming convention for ChocolArm64 project * Fix NaN * Remove unneeded this. from Ryujinx project * Adjust naming from new PRs * Name changes based on feedback * How did this get removed? * Rebasing fix * Change FP enum case * Remove prefix from ChocolArm64 classes - Part 1 * Remove prefix from ChocolArm64 classes - Part 2 * Fix alignment from last commit's renaming * Rename namespaces * Rename stragglers * Fix alignment * Rename OpCode class * Missed a few * Adjust alignment --- ChocolArm64/TranslatorCache.cs | 165 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 ChocolArm64/TranslatorCache.cs (limited to 'ChocolArm64/TranslatorCache.cs') diff --git a/ChocolArm64/TranslatorCache.cs b/ChocolArm64/TranslatorCache.cs new file mode 100644 index 00000000..7d650357 --- /dev/null +++ b/ChocolArm64/TranslatorCache.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Threading; + +namespace ChocolArm64 +{ + class TranslatorCache + { + //Maximum size of the cache, in bytes, measured in ARM code size. + private const int MaxTotalSize = 4 * 1024 * 256; + + //Minimum time required in milliseconds for a method to be eligible for deletion. + private const int MinTimeDelta = 2 * 60000; + + //Minimum number of calls required to update the timestamp. + private const int MinCallCountForUpdate = 250; + + private class CacheBucket + { + public TranslatedSub Subroutine { get; private set; } + + public LinkedListNode Node { get; private set; } + + public int CallCount { get; set; } + + public int Size { get; private set; } + + public long Timestamp { get; private set; } + + public CacheBucket(TranslatedSub subroutine, LinkedListNode node, int size) + { + Subroutine = subroutine; + Size = size; + + UpdateNode(node); + } + + public void UpdateNode(LinkedListNode node) + { + Node = node; + + Timestamp = GetTimestamp(); + } + } + + private ConcurrentDictionary _cache; + + private LinkedList _sortedCache; + + private int _totalSize; + + public TranslatorCache() + { + _cache = new ConcurrentDictionary(); + + _sortedCache = new LinkedList(); + } + + public void AddOrUpdate(long position, TranslatedSub subroutine, int size) + { + ClearCacheIfNeeded(); + + _totalSize += size; + + lock (_sortedCache) + { + LinkedListNode node = _sortedCache.AddLast(position); + + CacheBucket newBucket = new CacheBucket(subroutine, node, size); + + _cache.AddOrUpdate(position, newBucket, (key, bucket) => + { + _totalSize -= bucket.Size; + + _sortedCache.Remove(bucket.Node); + + return newBucket; + }); + } + } + + public bool HasSubroutine(long position) + { + return _cache.ContainsKey(position); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetSubroutine(long position, out TranslatedSub subroutine) + { + if (_cache.TryGetValue(position, out CacheBucket bucket)) + { + if (bucket.CallCount++ > MinCallCountForUpdate) + { + if (Monitor.TryEnter(_sortedCache)) + { + try + { + bucket.CallCount = 0; + + _sortedCache.Remove(bucket.Node); + + bucket.UpdateNode(_sortedCache.AddLast(position)); + } + finally + { + Monitor.Exit(_sortedCache); + } + } + } + + subroutine = bucket.Subroutine; + + return true; + } + + subroutine = default(TranslatedSub); + + return false; + } + + private void ClearCacheIfNeeded() + { + long timestamp = GetTimestamp(); + + while (_totalSize > MaxTotalSize) + { + lock (_sortedCache) + { + LinkedListNode node = _sortedCache.First; + + if (node == null) + { + break; + } + + CacheBucket bucket = _cache[node.Value]; + + long timeDelta = timestamp - bucket.Timestamp; + + if (timeDelta <= MinTimeDelta) + { + break; + } + + if (_cache.TryRemove(node.Value, out bucket)) + { + _totalSize -= bucket.Size; + + _sortedCache.Remove(bucket.Node); + } + } + } + } + + private static long GetTimestamp() + { + long timestamp = Stopwatch.GetTimestamp(); + + return timestamp / (Stopwatch.Frequency / 1000); + } + } +} \ No newline at end of file -- cgit v1.2.3