mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-08-20 07:38:42 +02:00
* Start of JIT garbage collection improvements - thread static pool for Operand, MemoryOperand, Operation - Operands and Operations are always to be constructed via their static helper classes, so they can be pooled. - removing LinkedList from Node for sources/destinations (replaced with List<>s for now, but probably could do arrays since size is bounded) - removing params constructors from Node - LinkedList<> to List<> with Clear() for Operand assignments/uses - ThreadStaticPool is very simple and basically just exists for the purpose of our specific translation allocation problem. Right now it will stay at the worst case allocation count for that thread (so far) - the pool can never shrink. - Still some cases of Operand[] that haven't been removed yet. Will need to evaluate them (eg. is there a reasonable max number of params for Calls?) * ConcurrentStack instead of ConcurrentQueue for Rejit * Optimize some parts of LSRA - BitMap now operates on 64-bit int rather than 32-bit - BitMap is now pooled in a ThreadStatic pool (within lrsa) - BitMap now is now its own iterator. Marginally speeds up iterating through the bits. - A few cases where enumerators were generated have been converted to forms that generate less garbage. - New data structure for sorting _usePositions in LiveIntervals. Much faster split, NextUseAfter, initial insertion. Random insertion is slightly slower. - That last one is WIP since you need to insert the values backwards. It would be ideal if it just flipped it for you, uncomplicating things on the caller side. * Use a static pool of thread static pools. (yes.) Prevents each execution thread creating its own lowCq pool and making me cry. * Move constant value to top, change naming convention. * Fix iteration of memory operands. * Increase max thread count. * Address Feedback
185 lines
4.1 KiB
C#
185 lines
4.1 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Numerics;
|
|
|
|
namespace ARMeilleure.Common
|
|
{
|
|
class BitMap : IEnumerator<int>
|
|
{
|
|
private const int IntSize = 64;
|
|
private const int IntMask = IntSize - 1;
|
|
|
|
private List<long> _masks;
|
|
|
|
private int _enumIndex;
|
|
private long _enumMask;
|
|
private int _enumBit;
|
|
|
|
public int Current => _enumIndex * IntSize + _enumBit;
|
|
object IEnumerator.Current => Current;
|
|
|
|
public BitMap()
|
|
{
|
|
_masks = new List<long>(0);
|
|
}
|
|
|
|
public BitMap(int initialCapacity)
|
|
{
|
|
int count = (initialCapacity + IntMask) / IntSize;
|
|
|
|
_masks = new List<long>(count);
|
|
|
|
while (count-- > 0)
|
|
{
|
|
_masks.Add(0);
|
|
}
|
|
}
|
|
|
|
public void Reset(int initialCapacity)
|
|
{
|
|
int count = (initialCapacity + IntMask) / IntSize;
|
|
|
|
if (count > _masks.Capacity)
|
|
{
|
|
_masks.Capacity = count;
|
|
}
|
|
|
|
_masks.Clear();
|
|
|
|
while (count-- > 0)
|
|
{
|
|
_masks.Add(0);
|
|
}
|
|
}
|
|
|
|
public bool Set(int bit)
|
|
{
|
|
EnsureCapacity(bit + 1);
|
|
|
|
int wordIndex = bit / IntSize;
|
|
int wordBit = bit & IntMask;
|
|
|
|
long wordMask = 1L << wordBit;
|
|
|
|
if ((_masks[wordIndex] & wordMask) != 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
_masks[wordIndex] |= wordMask;
|
|
|
|
return true;
|
|
}
|
|
|
|
public void Clear(int bit)
|
|
{
|
|
EnsureCapacity(bit + 1);
|
|
|
|
int wordIndex = bit / IntSize;
|
|
int wordBit = bit & IntMask;
|
|
|
|
long wordMask = 1L << wordBit;
|
|
|
|
_masks[wordIndex] &= ~wordMask;
|
|
}
|
|
|
|
public bool IsSet(int bit)
|
|
{
|
|
EnsureCapacity(bit + 1);
|
|
|
|
int wordIndex = bit / IntSize;
|
|
int wordBit = bit & IntMask;
|
|
|
|
return (_masks[wordIndex] & (1L << wordBit)) != 0;
|
|
}
|
|
|
|
public bool Set(BitMap map)
|
|
{
|
|
EnsureCapacity(map._masks.Count * IntSize);
|
|
|
|
bool modified = false;
|
|
|
|
for (int index = 0; index < _masks.Count; index++)
|
|
{
|
|
long newValue = _masks[index] | map._masks[index];
|
|
|
|
if (_masks[index] != newValue)
|
|
{
|
|
_masks[index] = newValue;
|
|
|
|
modified = true;
|
|
}
|
|
}
|
|
|
|
return modified;
|
|
}
|
|
|
|
public bool Clear(BitMap map)
|
|
{
|
|
EnsureCapacity(map._masks.Count * IntSize);
|
|
|
|
bool modified = false;
|
|
|
|
for (int index = 0; index < _masks.Count; index++)
|
|
{
|
|
long newValue = _masks[index] & ~map._masks[index];
|
|
|
|
if (_masks[index] != newValue)
|
|
{
|
|
_masks[index] = newValue;
|
|
|
|
modified = true;
|
|
}
|
|
}
|
|
|
|
return modified;
|
|
}
|
|
|
|
#region IEnumerable<long> Methods
|
|
|
|
// Note: The bit enumerator is embedded in this class to avoid creating garbage when enumerating.
|
|
|
|
private void EnsureCapacity(int size)
|
|
{
|
|
while (_masks.Count * IntSize < size)
|
|
{
|
|
_masks.Add(0);
|
|
}
|
|
}
|
|
|
|
public IEnumerator<int> GetEnumerator()
|
|
{
|
|
Reset();
|
|
return this;
|
|
}
|
|
|
|
public bool MoveNext()
|
|
{
|
|
if (_enumMask != 0)
|
|
{
|
|
_enumMask &= ~(1L << _enumBit);
|
|
}
|
|
while (_enumMask == 0)
|
|
{
|
|
if (++_enumIndex >= _masks.Count)
|
|
{
|
|
return false;
|
|
}
|
|
_enumMask = _masks[_enumIndex];
|
|
}
|
|
_enumBit = BitOperations.TrailingZeroCount(_enumMask);
|
|
return true;
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
_enumIndex = -1;
|
|
_enumMask = 0;
|
|
_enumBit = 0;
|
|
}
|
|
|
|
public void Dispose() { }
|
|
|
|
#endregion
|
|
}
|
|
} |