Further imrpove RamSearch performance

- switch _watchList from a List to an array
- more Domain.EnterExit usage
This commit is contained in:
Morilli 2022-07-04 07:09:53 +02:00
parent 9e90290b87
commit 011f4bfe03
1 changed files with 84 additions and 78 deletions

View File

@ -14,10 +14,10 @@ namespace BizHawk.Client.Common.RamSearchEngine
{
private Compare _compareTo = Compare.Previous;
private List<IMiniWatch> _watchList = new List<IMiniWatch>();
private IMiniWatch[] _watchList;
private readonly SearchEngineSettings _settings;
private readonly UndoHistory<IEnumerable<IMiniWatch>> _history = new UndoHistory<IEnumerable<IMiniWatch>>(true, new List<IMiniWatch>()); //TODO use IList instead of IEnumerable and stop calling `.ToList()` (i.e. cloning) on reads and writes?
private bool _isSorted = true; // Tracks whether or not the list is sorted by address, if it is, binary search can be used for finding watches
private readonly UndoHistory<IEnumerable<IMiniWatch>> _history = new UndoHistory<IEnumerable<IMiniWatch>>(true, new List<IMiniWatch>()); //TODO use IList instead of IEnumerable and stop calling `.ToArray()` (i.e. cloning) on reads and writes?
private bool _isSorted = true; // Tracks whether or not the array is sorted by address, if it is, binary search can be used for finding watches
public RamSearchEngine(SearchEngineSettings settings, IMemoryDomains memoryDomains)
{
@ -55,53 +55,56 @@ namespace BizHawk.Client.Common.RamSearchEngine
listSize /= (int)_settings.Size;
}
_watchList = new List<IMiniWatch>((int)listSize);
_watchList = new IMiniWatch[listSize];
switch (_settings.Size)
using (Domain.EnterExit())
{
default:
case WatchSize.Byte:
for (int i = 0; i < domain.Size; i++)
{
if (_settings.IsDetailed())
switch (_settings.Size)
{
default:
case WatchSize.Byte:
for (int i = 0; i < domain.Size; i++)
{
_watchList.Add(new MiniByteWatchDetailed(domain, i));
if (_settings.IsDetailed())
{
_watchList[i] = new MiniByteWatchDetailed(domain, i);
}
else
{
_watchList[i] = new MiniByteWatch(domain, i);
}
}
else
{
_watchList.Add(new MiniByteWatch(domain, i));
}
}
break;
case WatchSize.Word:
for (int i = 0; i < domain.Size - 1; i += _settings.CheckMisAligned ? 1 : 2)
{
if (_settings.IsDetailed())
break;
case WatchSize.Word:
for (int i = 0; i < domain.Size - 1; i += _settings.CheckMisAligned ? 1 : 2)
{
_watchList.Add(new MiniWordWatchDetailed(domain, i, _settings.BigEndian));
if (_settings.IsDetailed())
{
_watchList[i] = new MiniWordWatchDetailed(domain, i, _settings.BigEndian);
}
else
{
_watchList[i] = new MiniWordWatch(domain, i, _settings.BigEndian);
}
}
else
{
_watchList.Add(new MiniWordWatch(domain, i, _settings.BigEndian));
}
}
break;
case WatchSize.DWord:
for (int i = 0; i < domain.Size - 3; i += _settings.CheckMisAligned ? 1 : 4)
{
if (_settings.IsDetailed())
break;
case WatchSize.DWord:
for (int i = 0; i < domain.Size - 3; i += _settings.CheckMisAligned ? 1 : 4)
{
_watchList.Add(new MiniDWordWatchDetailed(domain, i, _settings.BigEndian));
if (_settings.IsDetailed())
{
_watchList[i] = new MiniDWordWatchDetailed(domain, i, _settings.BigEndian);
}
else
{
_watchList[i] = new MiniDWordWatch(domain, i, _settings.BigEndian);
}
}
else
{
_watchList.Add(new MiniDWordWatch(domain, i, _settings.BigEndian));
}
}
break;
break;
}
}
}
@ -122,29 +125,32 @@ namespace BizHawk.Client.Common.RamSearchEngine
public int DoSearch()
{
int before = _watchList.Count;
int before = _watchList.Length;
_watchList = _compareTo switch
using (Domain.EnterExit())
{
Compare.Previous => ComparePrevious(_watchList).ToList(),
Compare.SpecificValue => CompareSpecificValue(_watchList).ToList(),
Compare.SpecificAddress => CompareSpecificAddress(_watchList).ToList(),
Compare.Changes => CompareChanges(_watchList).ToList(),
Compare.Difference => CompareDifference(_watchList).ToList(),
_ => ComparePrevious(_watchList).ToList()
};
_watchList = _compareTo switch
{
Compare.Previous => ComparePrevious(_watchList).ToArray(),
Compare.SpecificValue => CompareSpecificValue(_watchList).ToArray(),
Compare.SpecificAddress => CompareSpecificAddress(_watchList).ToArray(),
Compare.Changes => CompareChanges(_watchList).ToArray(),
Compare.Difference => CompareDifference(_watchList).ToArray(),
_ => ComparePrevious(_watchList).ToArray()
};
if (_settings.PreviousType == PreviousType.LastSearch)
{
SetPreviousToCurrent();
if (_settings.PreviousType == PreviousType.LastSearch)
{
SetPreviousToCurrent();
}
}
if (UndoEnabled)
{
_history.AddState(_watchList.ToList());
_history.AddState(_watchList.ToArray());
}
return before - _watchList.Count;
return before - _watchList.Length;
}
public bool Preview(long address)
@ -164,7 +170,7 @@ namespace BizHawk.Client.Common.RamSearchEngine
};
}
public int Count => _watchList.Count;
public int Count => _watchList.Length;
public SearchMode Mode => _settings.Mode;
@ -198,12 +204,12 @@ namespace BizHawk.Client.Common.RamSearchEngine
{
if (_settings.IsDetailed())
{
using (_settings.Domain.EnterExit())
{
foreach (IMiniWatchDetails watch in _watchList)
{
watch.Update(_settings.PreviousType, _settings.Domain, _settings.BigEndian);
}
using (_settings.Domain.EnterExit())
{
foreach (IMiniWatchDetails watch in _watchList)
{
watch.Update(_settings.PreviousType, _settings.Domain, _settings.BigEndian);
}
}
}
}
@ -225,7 +231,7 @@ namespace BizHawk.Client.Common.RamSearchEngine
public void SetPreviousToCurrent()
{
_watchList.ForEach(w => w.SetPreviousToCurrent(_settings.Domain, _settings.BigEndian));
Array.ForEach(_watchList, w => w.SetPreviousToCurrent(_settings.Domain, _settings.BigEndian));
}
public void ClearChangeCounts()
@ -247,7 +253,7 @@ namespace BizHawk.Client.Common.RamSearchEngine
{
if (UndoEnabled)
{
_history.AddState(_watchList.ToList());
_history.AddState(_watchList.ToArray());
}
var addresses = watches.Select(w => w.Address);
@ -258,11 +264,11 @@ namespace BizHawk.Client.Common.RamSearchEngine
{
if (UndoEnabled)
{
_history.AddState(_watchList.ToList());
_history.AddState(_watchList.ToArray());
}
var removeList = indices.Select(i => _watchList[i]); // This will fail after int.MaxValue but RAM Search fails on domains that large anyway
_watchList = _watchList.Except(removeList).ToList();
_watchList = _watchList.Except(removeList).ToArray();
}
public void RemoveAddressRange(IEnumerable<long> addresses)
@ -274,7 +280,7 @@ namespace BizHawk.Client.Common.RamSearchEngine
{
if (!append)
{
_watchList.Clear();
Array.Clear(_watchList, 0, _watchList.Length);
}
var list = _settings.Size switch
@ -294,13 +300,13 @@ namespace BizHawk.Client.Common.RamSearchEngine
switch (column)
{
case WatchList.Address:
_watchList = _watchList.OrderBy(w => w.Address, reverse).ToList();
_watchList = _watchList.OrderBy(w => w.Address, reverse).ToArray();
break;
case WatchList.Value:
_watchList = _watchList.OrderBy(w => GetValue(w.Address), reverse).ToList();
_watchList = _watchList.OrderBy(w => GetValue(w.Address), reverse).ToArray();
break;
case WatchList.Prev:
_watchList = _watchList.OrderBy(w => w.Previous, reverse).ToList();
_watchList = _watchList.OrderBy(w => w.Previous, reverse).ToArray();
break;
case WatchList.ChangesCol:
if (_settings.IsDetailed())
@ -309,12 +315,12 @@ namespace BizHawk.Client.Common.RamSearchEngine
.Cast<IMiniWatchDetails>()
.OrderBy(w => w.ChangeCount, reverse)
.Cast<IMiniWatch>()
.ToList();
.ToArray();
}
break;
case WatchList.Diff:
_watchList = _watchList.OrderBy(w => GetValue(w.Address) - w.Previous, reverse).ToList();
_watchList = _watchList.OrderBy(w => GetValue(w.Address) - w.Previous, reverse).ToArray();
break;
}
}
@ -333,26 +339,26 @@ namespace BizHawk.Client.Common.RamSearchEngine
public int Undo()
{
int origCount = _watchList.Count;
int origCount = _watchList.Length;
if (UndoEnabled)
{
_watchList = _history.Undo().ToList();
return _watchList.Count - origCount;
_watchList = _history.Undo().ToArray();
return _watchList.Length - origCount;
}
return _watchList.Count;
return _watchList.Length;
}
public int Redo()
{
int origCount = _watchList.Count;
int origCount = _watchList.Length;
if (UndoEnabled)
{
_watchList = _history.Redo().ToList();
return origCount - _watchList.Count;
_watchList = _history.Redo().ToArray();
return origCount - _watchList.Length;
}
return _watchList.Count;
return _watchList.Length;
}
private IEnumerable<IMiniWatch> ComparePrevious(IEnumerable<IMiniWatch> watchList)