aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Kernel/Threading/KPriorityQueue.cs
diff options
context:
space:
mode:
authorjhorv <38920027+jhorv@users.noreply.github.com>2023-03-17 08:14:50 -0400
committerGitHub <noreply@github.com>2023-03-17 13:14:50 +0100
commit5131b71437b36f9b876046a2fddd5465652e0f10 (patch)
treea1b8647b1f948e3f88708d9ba41b2d1338f34de9 /Ryujinx.HLE/HOS/Kernel/Threading/KPriorityQueue.cs
parent7870423671cba17c8aad9bb93a67c84bda441366 (diff)
Reducing memory allocations (#4537)1.1.668
* add RecyclableMemoryStream dependency and MemoryStreamManager * organize BinaryReader/BinaryWriter extensions * add StreamExtensions to reduce need for BinaryWriter * simple replacments of MemoryStream with RecyclableMemoryStream * add write ReadOnlySequence<byte> support to IVirtualMemoryManager * avoid 0-length array creation * rework IpcMessage and related types to greatly reduce memory allocation by using RecylableMemoryStream, keeping streams around longer, avoiding their creation when possible, and avoiding creation of BinaryReader and BinaryWriter when possible * reduce LINQ-induced memory allocations with custom methods to query KPriorityQueue * use RecyclableMemoryStream in StreamUtils, and use StreamUtils in EmbeddedResources * add constants for nanosecond/millisecond conversions * code formatting * XML doc adjustments * fix: StreamExtension.WriteByte not writing non-zero values for lengths <= 16 * XML Doc improvements. Implement StreamExtensions.WriteByte() block writes for large-enough count values. * add copyless path for StreamExtension.Write(ReadOnlySpan<int>) * add default implementation of IVirtualMemoryManager.Write(ulong, ReadOnlySequence<byte>); remove previous explicit implementations * code style fixes * remove LINQ completely from KScheduler/KPriorityQueue by implementing a custom struct-based enumerator
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/Threading/KPriorityQueue.cs')
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Threading/KPriorityQueue.cs137
1 files changed, 114 insertions, 23 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KPriorityQueue.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KPriorityQueue.cs
index 2c9d7574..14fba704 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KPriorityQueue.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KPriorityQueue.cs
@@ -5,11 +5,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{
class KPriorityQueue
{
- private LinkedList<KThread>[][] _scheduledThreadsPerPrioPerCore;
- private LinkedList<KThread>[][] _suggestedThreadsPerPrioPerCore;
+ private readonly LinkedList<KThread>[][] _scheduledThreadsPerPrioPerCore;
+ private readonly LinkedList<KThread>[][] _suggestedThreadsPerPrioPerCore;
- private long[] _scheduledPrioritiesPerCore;
- private long[] _suggestedPrioritiesPerCore;
+ private readonly long[] _scheduledPrioritiesPerCore;
+ private readonly long[] _suggestedPrioritiesPerCore;
public KPriorityQueue()
{
@@ -32,41 +32,132 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
_suggestedPrioritiesPerCore = new long[KScheduler.CpuCoresCount];
}
- public IEnumerable<KThread> SuggestedThreads(int core)
+ public readonly ref struct KThreadEnumerable
{
- return Iterate(_suggestedThreadsPerPrioPerCore, _suggestedPrioritiesPerCore, core);
+ readonly LinkedList<KThread>[][] _listPerPrioPerCore;
+ readonly long[] _prios;
+ readonly int _core;
+
+ public KThreadEnumerable(LinkedList<KThread>[][] listPerPrioPerCore, long[] prios, int core)
+ {
+ _listPerPrioPerCore = listPerPrioPerCore;
+ _prios = prios;
+ _core = core;
+ }
+
+ public Enumerator GetEnumerator()
+ {
+ return new Enumerator(_listPerPrioPerCore, _prios, _core);
+ }
+
+ public ref struct Enumerator
+ {
+ private readonly LinkedList<KThread>[][] _listPerPrioPerCore;
+ private readonly int _core;
+ private long _prioMask;
+ private int _prio;
+ private LinkedList<KThread> _list;
+ private LinkedListNode<KThread> _node;
+
+ public Enumerator(LinkedList<KThread>[][] listPerPrioPerCore, long[] prios, int core)
+ {
+ _listPerPrioPerCore = listPerPrioPerCore;
+ _core = core;
+ _prioMask = prios[core];
+ _prio = BitOperations.TrailingZeroCount(_prioMask);
+ _prioMask &= ~(1L << _prio);
+ }
+
+ public KThread Current => _node?.Value;
+
+ public bool MoveNext()
+ {
+ _node = _node?.Next;
+
+ if (_node == null)
+ {
+ if (!MoveNextListAndFirstNode())
+ {
+ return false;
+ }
+ }
+
+ return _node != null;
+ }
+
+ private bool MoveNextListAndFirstNode()
+ {
+ if (_prio < KScheduler.PrioritiesCount)
+ {
+ _list = _listPerPrioPerCore[_prio][_core];
+
+ _node = _list.First;
+
+ _prio = BitOperations.TrailingZeroCount(_prioMask);
+
+ _prioMask &= ~(1L << _prio);
+
+ return true;
+ }
+ else
+ {
+ _list = null;
+ _node = null;
+ return false;
+ }
+ }
+ }
}
- public IEnumerable<KThread> ScheduledThreads(int core)
+ public KThreadEnumerable ScheduledThreads(int core)
{
- return Iterate(_scheduledThreadsPerPrioPerCore, _scheduledPrioritiesPerCore, core);
+ return new KThreadEnumerable(_scheduledThreadsPerPrioPerCore, _scheduledPrioritiesPerCore, core);
}
- private IEnumerable<KThread> Iterate(LinkedList<KThread>[][] listPerPrioPerCore, long[] prios, int core)
+ public KThreadEnumerable SuggestedThreads(int core)
{
- long prioMask = prios[core];
-
- int prio = BitOperations.TrailingZeroCount(prioMask);
+ return new KThreadEnumerable(_suggestedThreadsPerPrioPerCore, _suggestedPrioritiesPerCore, core);
+ }
- prioMask &= ~(1L << prio);
+ public KThread ScheduledThreadsFirstOrDefault(int core)
+ {
+ return ScheduledThreadsElementAtOrDefault(core, 0);
+ }
- while (prio < KScheduler.PrioritiesCount)
+ public KThread ScheduledThreadsElementAtOrDefault(int core, int index)
+ {
+ int currentIndex = 0;
+ foreach (var scheduledThread in ScheduledThreads(core))
{
- LinkedList<KThread> list = listPerPrioPerCore[prio][core];
+ if (currentIndex == index)
+ {
+ return scheduledThread;
+ }
+ else
+ {
+ currentIndex++;
+ }
+ }
- LinkedListNode<KThread> node = list.First;
+ return null;
+ }
- while (node != null)
+ public KThread ScheduledThreadsWithDynamicPriorityFirstOrDefault(int core, int dynamicPriority)
+ {
+ foreach (var scheduledThread in ScheduledThreads(core))
+ {
+ if (scheduledThread.DynamicPriority == dynamicPriority)
{
- yield return node.Value;
-
- node = node.Next;
+ return scheduledThread;
}
+ }
- prio = BitOperations.TrailingZeroCount(prioMask);
+ return null;
+ }
- prioMask &= ~(1L << prio);
- }
+ public bool HasScheduledThreads(int core)
+ {
+ return ScheduledThreadsFirstOrDefault(core) != null;
}
public void TransferToCore(int prio, int dstCore, KThread thread)