From c7c4a08cfd836709dfc5fd49a3bde26bd0307f26 Mon Sep 17 00:00:00 2001 From: SuuperW Date: Mon, 27 Jul 2020 15:17:16 -0500 Subject: [PATCH] Further refactoring of state decay. Also, use a larger zeros array size. 16 is pathetic. Probably should go even higher than this. --- .../movie/tasproj/StateManagerDecay.cs | 96 +++++++++---------- .../movie/tasproj/TasStateManager.cs | 2 +- 2 files changed, 44 insertions(+), 54 deletions(-) diff --git a/src/BizHawk.Client.Common/movie/tasproj/StateManagerDecay.cs b/src/BizHawk.Client.Common/movie/tasproj/StateManagerDecay.cs index 559f39e32f..076e8ae371 100644 --- a/src/BizHawk.Client.Common/movie/tasproj/StateManagerDecay.cs +++ b/src/BizHawk.Client.Common/movie/tasproj/StateManagerDecay.cs @@ -60,70 +60,60 @@ namespace BizHawk.Client.Common _tsm = tsm; } - // todo: go through all states once, remove as many as we need. + /// + /// This will strategically remove states based on their alignment with the state gap (and its multiples) and their distance from the current frame. + /// public void Trigger(int currentEmulatedFrame, int statesToDecay) { - for (; statesToDecay > 0 && _tsm.Count > 1; statesToDecay--) + int baseStateIndex = _tsm.GetStateIndexByFrame(currentEmulatedFrame); + int baseStateFrame = _tsm.GetStateFrameByIndex(baseStateIndex) / _step; // reduce to step integral TODO: do we actually want this? + // key: priority value: frame + List> decayPriorities = new List>(); + + for (int currentStateIndex = 1; currentStateIndex < _tsm.Count; currentStateIndex++) { - int baseStateIndex = _tsm.GetStateIndexByFrame(currentEmulatedFrame); - int baseStateFrame = _tsm.GetStateFrameByIndex(baseStateIndex) / _step; // reduce to step integral - int highestPriority = -1000000; - int frameToDecay = -1; - bool decayed = false; + int currentFrame = _tsm.GetStateFrameByIndex(currentStateIndex); - for (int currentStateIndex = 1; currentStateIndex < _tsm.Count; currentStateIndex++) - { - int currentFrame = _tsm.GetStateFrameByIndex(currentStateIndex); - - if (_movie.Markers.IsMarker(currentFrame + 1)) - continue; - - if (currentFrame + 1 == _movie.LastEditedFrame) - continue; - - if (currentFrame % _step > 0) - { - // ignore the pattern if the state doesn't belong already, drop it blindly and skip everything - if (_tsm.Remove(currentFrame)) - { - decayed = true; - break; - } - } - else // reduce to step integral for all the decay logic - currentFrame /= _step; - - int zeroCount = _zeros[currentFrame & _mask]; - int priority = (baseStateFrame - currentFrame) >> zeroCount; - - if (priority > highestPriority) - { - highestPriority = priority; - frameToDecay = currentFrame; - } - } - if (decayed) + if (_movie.Markers.IsMarker(currentFrame + 1)) continue; - - if (frameToDecay > -1) + if (currentFrame + 1 == _movie.LastEditedFrame) + continue; + + // not aligned to state gap at all + if (currentFrame % _step > 0) { - if (_tsm.Remove(frameToDecay * _step)) - decayed = true; + decayPriorities.Add(new KeyValuePair(int.MaxValue, currentFrame)); + continue; } - // we're very sorry about failing to find states to remove, but we can't go beyond capacity, so remove at least something - if (!decayed) - { - if (!_tsm.Remove(_tsm.GetStateFrameByIndex(1))) - { - // This should never happen, but just in case, we don't want to let memory usage continue to climb. - throw new System.Exception("Failed to remove states."); - } - } + // reduce to step integral for the decay logic + currentFrame /= _step; + int zeroCount = _zeros[currentFrame & _mask]; + int priority = (baseStateFrame - currentFrame) >> zeroCount; + decayPriorities.Add(new KeyValuePair(priority, currentFrame * _step)); + } + + // reverse sort; high priority to remove comes first + decayPriorities.Sort((p2, p1) => p1.Key.CompareTo(p2.Key)); + + int index = 0; + while (statesToDecay > 0 && index < decayPriorities.Count) + { + if (_tsm.Remove(decayPriorities[index].Value * _step)) + statesToDecay--; + } + + // we're very sorry about failing to find states to remove, but we can't go beyond capacity, so remove at least something + while (statesToDecay > 0) + { + if (_tsm.Remove(_tsm.GetStateFrameByIndex(1))) + statesToDecay--; + else // This should never happen, but just in case, we don't want to let memory usage continue to climb. + throw new System.Exception("Failed to remove states."); } } - public void UpdateSettings(int capacity, int step, int bits) + public void UpdateSettings(int step, int bits) { _step = step; _bits = bits; diff --git a/src/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs b/src/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs index 7726483026..26cdc09d4d 100644 --- a/src/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs +++ b/src/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs @@ -116,7 +116,7 @@ namespace BizHawk.Client.Common _stateFrequency = ((int)(_expectedStateSizeInMb * 1024 / Settings.MemStateGapDividerKB)) .Clamp(MinFrequency, MaxFrequency); - _decay.UpdateSettings(MaxStates, _stateFrequency, 4); + _decay.UpdateSettings(_stateFrequency, 6); LimitStateCount(); }