aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Ipc
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/Ipc
parent7870423671cba17c8aad9bb93a67c84bda441366 (diff)
Reducing memory allocations (#4537)
* 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/Ipc')
-rw-r--r--Ryujinx.HLE/HOS/Ipc/IpcHandleDesc.cs61
-rw-r--r--Ryujinx.HLE/HOS/Ipc/IpcMessage.cs163
-rw-r--r--Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs8
3 files changed, 115 insertions, 117 deletions
diff --git a/Ryujinx.HLE/HOS/Ipc/IpcHandleDesc.cs b/Ryujinx.HLE/HOS/Ipc/IpcHandleDesc.cs
index e6ed4613..c7ef7e9c 100644
--- a/Ryujinx.HLE/HOS/Ipc/IpcHandleDesc.cs
+++ b/Ryujinx.HLE/HOS/Ipc/IpcHandleDesc.cs
@@ -1,3 +1,6 @@
+using Microsoft.IO;
+using Ryujinx.Common;
+using Ryujinx.Common.Memory;
using System;
using System.IO;
@@ -18,20 +21,27 @@ namespace Ryujinx.HLE.HOS.Ipc
HasPId = (word & 1) != 0;
- ToCopy = new int[(word >> 1) & 0xf];
- ToMove = new int[(word >> 5) & 0xf];
-
PId = HasPId ? reader.ReadUInt64() : 0;
- for (int index = 0; index < ToCopy.Length; index++)
+ int toCopySize = (word >> 1) & 0xf;
+ int[] toCopy = toCopySize == 0 ? Array.Empty<int>() : new int[toCopySize];
+
+ for (int index = 0; index < toCopy.Length; index++)
{
- ToCopy[index] = reader.ReadInt32();
+ toCopy[index] = reader.ReadInt32();
}
- for (int index = 0; index < ToMove.Length; index++)
+ ToCopy = toCopy;
+
+ int toMoveSize = (word >> 5) & 0xf;
+ int[] toMove = toMoveSize == 0 ? Array.Empty<int>() : new int[toMoveSize];
+
+ for (int index = 0; index < toMove.Length; index++)
{
- ToMove[index] = reader.ReadInt32();
+ toMove[index] = reader.ReadInt32();
}
+
+ ToMove = toMove;
}
public IpcHandleDesc(int[] copy, int[] move)
@@ -57,36 +67,27 @@ namespace Ryujinx.HLE.HOS.Ipc
return new IpcHandleDesc(Array.Empty<int>(), handles);
}
- public byte[] GetBytes()
+ public RecyclableMemoryStream GetStream()
{
- using (MemoryStream ms = new MemoryStream())
- {
- BinaryWriter writer = new BinaryWriter(ms);
-
- int word = HasPId ? 1 : 0;
+ RecyclableMemoryStream ms = MemoryStreamManager.Shared.GetStream();
- word |= (ToCopy.Length & 0xf) << 1;
- word |= (ToMove.Length & 0xf) << 5;
+ int word = HasPId ? 1 : 0;
- writer.Write(word);
+ word |= (ToCopy.Length & 0xf) << 1;
+ word |= (ToMove.Length & 0xf) << 5;
- if (HasPId)
- {
- writer.Write(PId);
- }
+ ms.Write(word);
- foreach (int handle in ToCopy)
- {
- writer.Write(handle);
- }
+ if (HasPId)
+ {
+ ms.Write(PId);
+ }
- foreach (int handle in ToMove)
- {
- writer.Write(handle);
- }
+ ms.Write(ToCopy);
+ ms.Write(ToMove);
- return ms.ToArray();
- }
+ ms.Position = 0;
+ return ms;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs b/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs
index 55044da4..4e8f2fbf 100644
--- a/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs
+++ b/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs
@@ -1,4 +1,8 @@
+using Microsoft.IO;
+using Ryujinx.Common;
+using Ryujinx.Common.Memory;
using System;
+using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@@ -32,9 +36,9 @@ namespace Ryujinx.HLE.HOS.Ipc
ObjectIds = new List<int>();
}
- public IpcMessage(byte[] data, long cmdPtr) : this()
+ public IpcMessage(ReadOnlySpan<byte> data, long cmdPtr) : this()
{
- using (MemoryStream ms = new MemoryStream(data))
+ using (RecyclableMemoryStream ms = MemoryStreamManager.Shared.GetStream(data))
{
BinaryReader reader = new BinaryReader(ms);
@@ -114,124 +118,119 @@ namespace Ryujinx.HLE.HOS.Ipc
for (int index = 0; index < recvListCount; index++)
{
- RecvListBuff.Add(new IpcRecvListBuffDesc(reader));
+ RecvListBuff.Add(new IpcRecvListBuffDesc(reader.ReadUInt64()));
}
}
- public byte[] GetBytes(long cmdPtr, ulong recvListAddr)
+ public RecyclableMemoryStream GetStream(long cmdPtr, ulong recvListAddr)
{
- using (MemoryStream ms = new MemoryStream())
- {
- BinaryWriter writer = new BinaryWriter(ms);
+ RecyclableMemoryStream ms = MemoryStreamManager.Shared.GetStream();
- int word0;
- int word1;
+ int word0;
+ int word1;
- word0 = (int)Type;
- word0 |= (PtrBuff.Count & 0xf) << 16;
- word0 |= (SendBuff.Count & 0xf) << 20;
- word0 |= (ReceiveBuff.Count & 0xf) << 24;
- word0 |= (ExchangeBuff.Count & 0xf) << 28;
+ word0 = (int)Type;
+ word0 |= (PtrBuff.Count & 0xf) << 16;
+ word0 |= (SendBuff.Count & 0xf) << 20;
+ word0 |= (ReceiveBuff.Count & 0xf) << 24;
+ word0 |= (ExchangeBuff.Count & 0xf) << 28;
- byte[] handleData = Array.Empty<byte>();
+ using RecyclableMemoryStream handleDataStream = HandleDesc?.GetStream();
- if (HandleDesc != null)
- {
- handleData = HandleDesc.GetBytes();
- }
+ int dataLength = RawData?.Length ?? 0;
- int dataLength = RawData?.Length ?? 0;
+ dataLength = (dataLength + 3) & ~3;
- dataLength = (dataLength + 3) & ~3;
+ int rawLength = dataLength;
- int rawLength = dataLength;
+ int pad0 = (int)GetPadSize16(cmdPtr + 8 + (handleDataStream?.Length ?? 0) + PtrBuff.Count * 8);
- int pad0 = (int)GetPadSize16(cmdPtr + 8 + handleData.Length + PtrBuff.Count * 8);
+ // Apparently, padding after Raw Data is 16 bytes, however when there is
+ // padding before Raw Data too, we need to subtract the size of this padding.
+ // This is the weirdest padding I've seen so far...
+ int pad1 = 0x10 - pad0;
- // Apparently, padding after Raw Data is 16 bytes, however when there is
- // padding before Raw Data too, we need to subtract the size of this padding.
- // This is the weirdest padding I've seen so far...
- int pad1 = 0x10 - pad0;
+ dataLength = (dataLength + pad0 + pad1) / 4;
- dataLength = (dataLength + pad0 + pad1) / 4;
+ word1 = (dataLength & 0x3ff) | (2 << 10);
- word1 = (dataLength & 0x3ff) | (2 << 10);
+ if (HandleDesc != null)
+ {
+ word1 |= 1 << 31;
+ }
- if (HandleDesc != null)
- {
- word1 |= 1 << 31;
- }
+ ms.Write(word0);
+ ms.Write(word1);
- writer.Write(word0);
- writer.Write(word1);
- writer.Write(handleData);
+ if (handleDataStream != null)
+ {
+ ms.Write(handleDataStream);
+ }
- for (int index = 0; index < PtrBuff.Count; index++)
- {
- writer.Write(PtrBuff[index].GetWord0());
- writer.Write(PtrBuff[index].GetWord1());
- }
+ foreach (IpcPtrBuffDesc ptrBuffDesc in PtrBuff)
+ {
+ ms.Write(ptrBuffDesc.GetWord0());
+ ms.Write(ptrBuffDesc.GetWord1());
+ }
- ms.Seek(pad0, SeekOrigin.Current);
+ ms.WriteByte(0, pad0);
- if (RawData != null)
- {
- writer.Write(RawData);
- ms.Seek(rawLength - RawData.Length, SeekOrigin.Current);
- }
+ if (RawData != null)
+ {
+ ms.Write(RawData);
+ ms.WriteByte(0, rawLength - RawData.Length);
+ }
- writer.Write(new byte[pad1]);
- writer.Write(recvListAddr);
+ ms.WriteByte(0, pad1);
- return ms.ToArray();
- }
+ ms.Write(recvListAddr);
+
+ ms.Position = 0;
+
+ return ms;
}
- public byte[] GetBytesTipc()
+ public RecyclableMemoryStream GetStreamTipc()
{
Debug.Assert(PtrBuff.Count == 0);
- using (MemoryStream ms = new MemoryStream())
- {
- BinaryWriter writer = new BinaryWriter(ms);
+ RecyclableMemoryStream ms = MemoryStreamManager.Shared.GetStream();
- int word0;
- int word1;
+ int word0;
+ int word1;
- word0 = (int)Type;
- word0 |= (SendBuff.Count & 0xf) << 20;
- word0 |= (ReceiveBuff.Count & 0xf) << 24;
- word0 |= (ExchangeBuff.Count & 0xf) << 28;
+ word0 = (int)Type;
+ word0 |= (SendBuff.Count & 0xf) << 20;
+ word0 |= (ReceiveBuff.Count & 0xf) << 24;
+ word0 |= (ExchangeBuff.Count & 0xf) << 28;
- byte[] handleData = Array.Empty<byte>();
+ using RecyclableMemoryStream handleDataStream = HandleDesc?.GetStream();
- if (HandleDesc != null)
- {
- handleData = HandleDesc.GetBytes();
- }
-
- int dataLength = RawData?.Length ?? 0;
+ int dataLength = RawData?.Length ?? 0;
- dataLength = ((dataLength + 3) & ~3) / 4;
+ dataLength = ((dataLength + 3) & ~3) / 4;
- word1 = (dataLength & 0x3ff);
+ word1 = (dataLength & 0x3ff);
- if (HandleDesc != null)
- {
- word1 |= 1 << 31;
- }
+ if (HandleDesc != null)
+ {
+ word1 |= 1 << 31;
+ }
- writer.Write(word0);
- writer.Write(word1);
- writer.Write(handleData);
+ ms.Write(word0);
+ ms.Write(word1);
- if (RawData != null)
- {
- writer.Write(RawData);
- }
+ if (handleDataStream != null)
+ {
+ ms.Write(handleDataStream);
+ }
- return ms.ToArray();
+ if (RawData != null)
+ {
+ ms.Write(RawData);
}
+
+ return ms;
}
private long GetPadSize16(long position)
diff --git a/Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs b/Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs
index 10406ac7..bcc9d8f8 100644
--- a/Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs
+++ b/Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs
@@ -13,13 +13,11 @@ namespace Ryujinx.HLE.HOS.Ipc
Size = size;
}
- public IpcRecvListBuffDesc(BinaryReader reader)
+ public IpcRecvListBuffDesc(ulong packedValue)
{
- ulong value = reader.ReadUInt64();
+ Position = packedValue & 0xffffffffffff;
- Position = value & 0xffffffffffff;
-
- Size = (ushort)(value >> 48);
+ Size = (ushort)(packedValue >> 48);
}
}
} \ No newline at end of file