RecyclableMemoryStream pool

This commit is contained in:
LotP1 2025-11-20 02:23:56 +01:00
parent 44ab243694
commit 0e0d6e82dd
4 changed files with 35 additions and 8 deletions

View File

@ -7,6 +7,9 @@ namespace Ryujinx.Common.Memory
{ {
private static readonly RecyclableMemoryStreamManager _shared = new(); private static readonly RecyclableMemoryStreamManager _shared = new();
private static readonly ObjectPool<RecyclableMemoryStream> _streamPool =
new(() => new RecyclableMemoryStream(_shared, Guid.NewGuid(), null, 0));
/// <summary> /// <summary>
/// We don't expose the <c>RecyclableMemoryStreamManager</c> directly because version 2.x /// We don't expose the <c>RecyclableMemoryStreamManager</c> directly because version 2.x
/// returns them as <c>MemoryStream</c>. This Shared class is here to a) offer only the GetStream() versions we use /// returns them as <c>MemoryStream</c>. This Shared class is here to a) offer only the GetStream() versions we use
@ -19,7 +22,12 @@ namespace Ryujinx.Common.Memory
/// </summary> /// </summary>
/// <returns>A <c>RecyclableMemoryStream</c></returns> /// <returns>A <c>RecyclableMemoryStream</c></returns>
public static RecyclableMemoryStream GetStream() public static RecyclableMemoryStream GetStream()
=> new(_shared); {
RecyclableMemoryStream stream = _streamPool.Allocate();
stream.SetLength(0);
return stream;
}
/// <summary> /// <summary>
/// Retrieve a new <c>MemoryStream</c> object with the contents copied from the provided /// Retrieve a new <c>MemoryStream</c> object with the contents copied from the provided
@ -55,7 +63,8 @@ namespace Ryujinx.Common.Memory
RecyclableMemoryStream stream = null; RecyclableMemoryStream stream = null;
try try
{ {
stream = new RecyclableMemoryStream(_shared, id, tag, buffer.Length); stream = _streamPool.Allocate();
stream.SetLength(0);
stream.Write(buffer); stream.Write(buffer);
stream.Position = 0; stream.Position = 0;
return stream; return stream;
@ -83,7 +92,8 @@ namespace Ryujinx.Common.Memory
RecyclableMemoryStream stream = null; RecyclableMemoryStream stream = null;
try try
{ {
stream = new RecyclableMemoryStream(_shared, id, tag, count); stream = _streamPool.Allocate();
stream.SetLength(0);
stream.Write(buffer, offset, count); stream.Write(buffer, offset, count);
stream.Position = 0; stream.Position = 0;
return stream; return stream;
@ -94,6 +104,11 @@ namespace Ryujinx.Common.Memory
throw; throw;
} }
} }
public static void ReleaseStream(RecyclableMemoryStream stream)
{
_streamPool.Release(stream);
}
} }
} }
} }

View File

@ -2,6 +2,7 @@ using Microsoft.IO;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Memory; using Ryujinx.Common.Memory;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
@ -37,7 +38,7 @@ namespace Ryujinx.HLE.HOS.Ipc
public IpcMessage(ReadOnlySpan<byte> data, long cmdPtr) public IpcMessage(ReadOnlySpan<byte> data, long cmdPtr)
{ {
using RecyclableMemoryStream ms = MemoryStreamManager.Shared.GetStream(data); RecyclableMemoryStream ms = MemoryStreamManager.Shared.GetStream(data);
BinaryReader reader = new(ms); BinaryReader reader = new(ms);
@ -123,6 +124,8 @@ namespace Ryujinx.HLE.HOS.Ipc
} }
ObjectIds = []; ObjectIds = [];
MemoryStreamManager.Shared.ReleaseStream(ms);
} }
public RecyclableMemoryStream GetStream(long cmdPtr, ulong recvListAddr) public RecyclableMemoryStream GetStream(long cmdPtr, ulong recvListAddr)

View File

@ -23,6 +23,9 @@ namespace Ryujinx.HLE.HOS.Services
private int _selfId; private int _selfId;
private bool _isDomain; private bool _isDomain;
// cache array so we don't recreate it all the time
private object[] _parameters = [null];
public IpcService(ServerBase server = null, bool registerTipc = false) public IpcService(ServerBase server = null, bool registerTipc = false)
{ {
Stopwatch sw = Stopwatch.StartNew(); Stopwatch sw = Stopwatch.StartNew();
@ -146,7 +149,9 @@ namespace Ryujinx.HLE.HOS.Services
{ {
Logger.Trace?.Print(LogClass.KernelIpc, $"{service.GetType().Name}: {processRequest.Name}"); Logger.Trace?.Print(LogClass.KernelIpc, $"{service.GetType().Name}: {processRequest.Name}");
result = (ResultCode)processRequest.Invoke(service, [context]); _parameters[0] = context;
result = (ResultCode)processRequest.Invoke(service, _parameters);
} }
else else
{ {
@ -196,7 +201,9 @@ namespace Ryujinx.HLE.HOS.Services
{ {
Logger.Debug?.Print(LogClass.KernelIpc, $"{GetType().Name}: {processRequest.Name}"); Logger.Debug?.Print(LogClass.KernelIpc, $"{GetType().Name}: {processRequest.Name}");
result = (ResultCode)processRequest.Invoke(this, [context]); _parameters[0] = context;
result = (ResultCode)processRequest.Invoke(this, _parameters);
} }
else else
{ {

View File

@ -454,8 +454,9 @@ namespace Ryujinx.HLE.HOS.Services
response.RawData = _responseDataStream.ToArray(); response.RawData = _responseDataStream.ToArray();
using RecyclableMemoryStream responseStream = response.GetStreamTipc(); RecyclableMemoryStream responseStream = response.GetStreamTipc();
_selfProcess.CpuMemory.Write(_selfThread.TlsAddress, responseStream.GetReadOnlySequence()); _selfProcess.CpuMemory.Write(_selfThread.TlsAddress, responseStream.GetReadOnlySequence());
MemoryStreamManager.Shared.ReleaseStream(responseStream);
} }
else else
{ {
@ -464,8 +465,9 @@ namespace Ryujinx.HLE.HOS.Services
if (!isTipcCommunication) if (!isTipcCommunication)
{ {
using RecyclableMemoryStream responseStream = response.GetStream((long)_selfThread.TlsAddress, recvListAddr | ((ulong)PointerBufferSize << 48)); RecyclableMemoryStream responseStream = response.GetStream((long)_selfThread.TlsAddress, recvListAddr | ((ulong)PointerBufferSize << 48));
_selfProcess.CpuMemory.Write(_selfThread.TlsAddress, responseStream.GetReadOnlySequence()); _selfProcess.CpuMemory.Write(_selfThread.TlsAddress, responseStream.GetReadOnlySequence());
MemoryStreamManager.Shared.ReleaseStream(responseStream);
} }
return shouldReply; return shouldReply;