tsm: improving the algo

This commit is contained in:
feos 2018-02-26 01:45:26 +03:00
parent bc7a53abb5
commit 13a49b00d0
1 changed files with 51 additions and 32 deletions

View File

@ -289,55 +289,54 @@ namespace BizHawk.Client.Common
/// <summary>
/// Deletes/moves states to follow the state storage size limits.
/// Used after changing the settings too.
/// TODO: don't miss states on region borders
/// </summary>
public void LimitStateCount()
{
if (Used + _expectedStateSize > Settings.Cap
|| DiskUsed > (ulong)Settings.DiskCapacitymb * 1024 * 1024
|| DateTime.Now.Ticks > _stateCleanupTime)
if (Used + _expectedStateSize > Settings.Cap || DiskUsed > (ulong)Settings.DiskCapacitymb * 1024 * 1024)
{
// rely on frames, because relying on indexes while changing the collection is ugly
List<int> framesToClear = new List<int>();
// we have 5 greenzone regions, the last one we do not touch
// we have 5 greenzone regions (by powers of 2), the closest one we do not touch
int regionSize = _maxStates / 5;
int lastClearedFrame = 1;
// drop states from previous regions, increasing the gap for each one, make sure to ignore state 0
for (int gap = 2, last = _states.ToList().Count; gap <= 16; gap <<= 1)
// iterate through regions (region frame sizes increase by 2)
for (int borderIndex = GetStateIndexByFrame(Global.Emulator.Frame) - regionSize, mult = 2; borderIndex > 0; mult *= 2)
{
// last egion index
last -= regionSize;
if (last < 1)
{
return;
}
int nextBorderIndex = borderIndex - regionSize * mult;
if (nextBorderIndex <= 0)
nextBorderIndex = 1; // reached greenzone end
// first region index
int first = last - regionSize;
if (first < 1)
// iterate through states. i > 0 because nextBorderIndex > 0
for (int i = borderIndex; i > nextBorderIndex; i--)
{
first = 1;
}
int minStep = mult * StateFrequency;
int curFrame = GetStateFrameByIndex(i);
int nextFrame = GetStateFrameByIndex(i - 1);
// iterate through the region and record states' frames
for (int i = last; i >= first; i--)
{
if ((i & (gap - 1)) > 0)
if (curFrame - nextFrame < minStep)
{
framesToClear.Add(_states.ElementAt(i).Key);
RemoveState(nextFrame);
lastClearedFrame = nextFrame;
}
else
continue;
}
if (nextBorderIndex == 1)
return;
borderIndex = nextBorderIndex;
}
if (framesToClear.Any())
// finish off whatever we've missed
List<KeyValuePair<int, StateManagerState>> leftoverStates = _states
.Where(s => s.Key > 0 && s.Key < lastClearedFrame)
.ToList();
foreach (var state in leftoverStates)
{
foreach (var frame in framesToClear)
{
RemoveState(frame);
}
RemoveState(state.Key);
}
_stateCleanupTime = DateTime.Now.Ticks + _stateCleanupPeriod;
}
}
@ -489,6 +488,26 @@ namespace BizHawk.Client.Common
return this[s.Key];
}
/// <summary>
/// Returns index of the state right above the given frame
/// </summary>
/// <param name="frame"></param>
/// <returns></returns>
public int GetStateIndexByFrame(int frame)
{
return _states.IndexOfKey(GetStateClosestToFrame(frame).Key);
}
/// <summary>
/// Returns frame of the state at the given index
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public int GetStateFrameByIndex(int index)
{
return _states.ElementAt(index).Key;
}
private ulong _used;
private ulong Used
{