cleanup Zwinder

This commit is contained in:
adelikat 2020-06-19 16:16:07 -05:00
parent 53716a40e5
commit 487c596d76
2 changed files with 50 additions and 51 deletions

View File

@ -483,6 +483,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=retroarch/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=retroarch/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Rewinder/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Rewinder/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=riffmaster/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=riffmaster/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ringbuffer/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=RLCA/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=RLCA/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Roms/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Roms/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ROM_0027s/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=ROM_0027s/@EntryIndexedValue">True</s:Boolean>
@ -599,6 +600,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Zeromus/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Zeromus/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Zipheader/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Zipheader/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ZSNES/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=ZSNES/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Zwinder/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ZZZZ/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=ZZZZ/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ZZZZZZZZ/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> <s:Boolean x:Key="/Default/UserDictionary/Words/=ZZZZZZZZ/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -13,19 +13,18 @@ namespace BizHawk.Client.Common
/* /*
Main goals: Main goals:
1. No copies, ever. States are deposited directly to, and read directly from, one giant ring buffer. 1. No copies, ever. States are deposited directly to, and read directly from, one giant ring buffer.
As a consequence, there is no multithreading because there is nothing to thread. As a consequence, there is no multi-threading because there is nothing to thread.
2. Support for arbitrary and changeable state sizes. Frequency is calculated dynamically. 2. Support for arbitrary and changeable state sizes. Frequency is calculated dynamically.
3. No delta compression. Keep it simple. If there are cores that benefit heavily from delta compression, we should 3. No delta compression. Keep it simple. If there are cores that benefit heavily from delta compression, we should
maintain a separate rewinder alongside this one that is customized for those cores. maintain a separate rewinder alongside this one that is customized for those cores.
*/ */
public Zwinder(IBinaryStateable stateSource, IRewindSettings settings) public Zwinder(IBinaryStateable stateSource, IRewindSettings settings)
{ {
long targetSize = settings.BufferSize * 1024 * 1024; long targetSize = settings.BufferSize * 1024 * 1024;
if (targetSize < 65536)
throw new ArgumentOutOfRangeException(nameof(targetSize));
if (settings.TargetFrameLength < 1) if (settings.TargetFrameLength < 1)
{
throw new ArgumentOutOfRangeException(nameof(settings.TargetFrameLength)); throw new ArgumentOutOfRangeException(nameof(settings.TargetFrameLength));
}
Size = 1L << (int)Math.Floor(Math.Log(targetSize, 2)); Size = 1L << (int)Math.Floor(Math.Log(targetSize, 2));
_sizeMask = Size - 1; _sizeMask = Size - 1;
@ -33,19 +32,19 @@ namespace BizHawk.Client.Common
Active = true; Active = true;
_stateSource = stateSource; _stateSource = stateSource;
_targetFrameLength = settings.TargetFrameLength; _targetFrameLength = settings.TargetFrameLength;
_states = new StateInfo[STATEMASK + 1]; _states = new StateInfo[StateMask + 1];
_kompress = settings.UseCompression; _useCompression = settings.UseCompression;
} }
/// <summary> /// <summary>
/// Number of states that could be in the state ringbuffer, Mask for the state ringbuffer /// Number of states that could be in the state ringbuffer, Mask for the state ringbuffer
/// </summary> /// </summary>
private const int STATEMASK = 16383; private const int StateMask = 16383;
/// <summary> /// <summary>
/// How many states are actually in the state ringbuffer /// How many states are actually in the state ringbuffer
/// </summary> /// </summary>
public int Count => (_nextStateIndex - _firstStateIndex) & STATEMASK; public int Count => (_nextStateIndex - _firstStateIndex) & StateMask;
public float FullnessRatio => Used / (float)Size; public float FullnessRatio => Used / (float)Size;
@ -53,21 +52,19 @@ namespace BizHawk.Client.Common
/// total number of bytes used /// total number of bytes used
/// </summary> /// </summary>
/// <value></value> /// <value></value>
public long Used public long Used => Count == 0
{ ? 0
get : (_states[HeadStateIndex]
{ .Start + _states[HeadStateIndex]
if (Count == 0) .Size - _states[_firstStateIndex]
return 0; .Start) & _sizeMask;
return (_states[HeadStateIndex].Start + _states[HeadStateIndex].Size - _states[_firstStateIndex].Start) & _sizeMask;
}
}
/// <summary> /// <summary>
/// Total size of the _buffer /// Total size of the _buffer
/// </summary> /// </summary>
/// <value></value> /// <value></value>
public long Size { get; } public long Size { get; }
private readonly long _sizeMask; private readonly long _sizeMask;
private byte[] _buffer; private byte[] _buffer;
@ -79,12 +76,13 @@ namespace BizHawk.Client.Common
public int Size; public int Size;
public int Frame; public int Frame;
} }
private StateInfo[] _states; private StateInfo[] _states;
private int _firstStateIndex; private int _firstStateIndex;
private int _nextStateIndex; private int _nextStateIndex;
private int HeadStateIndex => (_nextStateIndex - 1) & STATEMASK; private int HeadStateIndex => (_nextStateIndex - 1) & StateMask;
private readonly bool _kompress; private readonly bool _useCompression;
private IBinaryStateable _stateSource; private IBinaryStateable _stateSource;
@ -98,7 +96,9 @@ namespace BizHawk.Client.Common
private int ComputeIdealRewindInterval() private int ComputeIdealRewindInterval()
{ {
if (Count == 0) if (Count == 0)
{
return 1; // shrug return 1; // shrug
}
// assume that the most recent state size is representative of stuff // assume that the most recent state size is representative of stuff
var sizeRatio = Size / (float)_states[HeadStateIndex].Size; var sizeRatio = Size / (float)_states[HeadStateIndex].Size;
@ -111,7 +111,10 @@ namespace BizHawk.Client.Common
private bool ShouldCapture(int frame) private bool ShouldCapture(int frame)
{ {
if (Count == 0) if (Count == 0)
{
return true; return true;
}
var frameDiff = frame - _states[HeadStateIndex].Frame; var frameDiff = frame - _states[HeadStateIndex].Frame;
if (frameDiff < 1) if (frameDiff < 1)
// non-linear time is from a combination of other state changing mechanisms and the rewinder // non-linear time is from a combination of other state changing mechanisms and the rewinder
@ -133,34 +136,29 @@ namespace BizHawk.Client.Common
start, start,
Size, _sizeMask); Size, _sizeMask);
if (_kompress) if (_useCompression)
{ {
using var kompressor = new DeflateStream(stream, CompressionLevel.Fastest, leaveOpen: true); using var compressor = new DeflateStream(stream, CompressionLevel.Fastest, leaveOpen: true);
_stateSource.SaveStateBinary(new BinaryWriter(kompressor)); _stateSource.SaveStateBinary(new BinaryWriter(compressor));
} }
else else
{ {
_stateSource.SaveStateBinary(new BinaryWriter(stream)); _stateSource.SaveStateBinary(new BinaryWriter(stream));
} }
// invalidate states if we're at the state ringbuffer size limit, or if they were overridden in the bytebuffer // invalidate states if we're at the state ringbuffer size limit, or if they were overridden in the byte buffer
var length = stream.Length; var length = stream.Length;
while (Count == STATEMASK || Count > 0 && ((_states[_firstStateIndex].Start - start) & _sizeMask) < length) while (Count == StateMask || Count > 0 && ((_states[_firstStateIndex].Start - start) & _sizeMask) < length)
_firstStateIndex = (_firstStateIndex + 1) & STATEMASK; _firstStateIndex = (_firstStateIndex + 1) & StateMask;
_states[_nextStateIndex].Frame = frame; _states[_nextStateIndex].Frame = frame;
_states[_nextStateIndex].Start = start; _states[_nextStateIndex].Start = start;
_states[_nextStateIndex].Size = (int)length; _states[_nextStateIndex].Size = (int)length;
_nextStateIndex = (_nextStateIndex + 1) & STATEMASK; _nextStateIndex = (_nextStateIndex + 1) & StateMask;
Console.WriteLine($"Size: {Size >> 20}MiB, Used: {Used >> 20}MiB, States: {Count}"); Console.WriteLine($"Size: {Size >> 20}MiB, Used: {Used >> 20}MiB, States: {Count}");
} }
public void Resume()
{
Active = true;
}
public bool Rewind(int frames) public bool Rewind(int frames)
{ {
if (!Active) if (!Active)
@ -171,17 +169,12 @@ namespace BizHawk.Client.Common
frames = Math.Min(frames, Count); frames = Math.Min(frames, Count);
if (frames == 0) if (frames == 0)
return false; // no states saved return false; // no states saved
int loadIndex = (_nextStateIndex - frames) & STATEMASK; int loadIndex = (_nextStateIndex - frames) & StateMask;
var stream = new LoadStateStream(_buffer, _states[loadIndex].Start, _states[loadIndex].Size, _sizeMask); var stream = new LoadStateStream(_buffer, _states[loadIndex].Start, _states[loadIndex].Size, _sizeMask);
if (_kompress) _stateSource.LoadStateBinary(_useCompression
{ ? new BinaryReader(new DeflateStream(stream, CompressionMode.Decompress, leaveOpen: true))
_stateSource.LoadStateBinary(new BinaryReader(new DeflateStream(stream, CompressionMode.Decompress, leaveOpen: true))); : new BinaryReader(stream));
}
else
{
_stateSource.LoadStateBinary(new BinaryReader(stream));
}
_nextStateIndex = loadIndex; _nextStateIndex = loadIndex;
Console.WriteLine($"Size: {Size >> 20}MiB, Used: {Used >> 20}MiB, States: {Count}"); Console.WriteLine($"Size: {Size >> 20}MiB, Used: {Used >> 20}MiB, States: {Count}");
@ -193,6 +186,12 @@ namespace BizHawk.Client.Common
Active = false; Active = false;
} }
public void Resume()
{
Active = true;
}
public void Dispose() public void Dispose()
{ {
_buffer = null; _buffer = null;
@ -210,11 +209,11 @@ namespace BizHawk.Client.Common
_mask = mask; _mask = mask;
} }
private byte[] _buffer; private readonly byte[] _buffer;
private readonly long _offset; private readonly long _offset;
private long _maxSize; private readonly long _maxSize;
private long _position;
private readonly long _mask; private readonly long _mask;
private long _position;
public override bool CanRead => false; public override bool CanRead => false;
public override bool CanSeek => false; public override bool CanSeek => false;
@ -223,8 +222,7 @@ namespace BizHawk.Client.Common
public override long Position { get => _position; set => throw new IOException(); } public override long Position { get => _position; set => throw new IOException(); }
public override void Flush() public override void Flush() {}
{}
public override int Read(byte[] buffer, int offset, int count) => throw new IOException(); public override int Read(byte[] buffer, int offset, int count) => throw new IOException();
public override long Seek(long offset, SeekOrigin origin) => throw new IOException(); public override long Seek(long offset, SeekOrigin origin) => throw new IOException();
@ -279,9 +277,9 @@ namespace BizHawk.Client.Common
_mask = mask; _mask = mask;
} }
private byte[] _buffer; private readonly byte[] _buffer;
private readonly long _offset; private readonly long _offset;
private long _size; private readonly long _size;
private long _position; private long _position;
private readonly long _mask; private readonly long _mask;
@ -325,10 +323,9 @@ namespace BizHawk.Client.Common
public override int ReadByte() public override int ReadByte()
{ {
if (_position < _size) return _position < _size
return _buffer[(_position++ + _offset) & _mask]; ? _buffer[(_position++ + _offset) & _mask]
else : -1;
return -1;
} }
public override long Seek(long offset, SeekOrigin origin) => throw new IOException(); public override long Seek(long offset, SeekOrigin origin) => throw new IOException();