Use pooled memory and avoid memory copies (#6691)
* perf: use ByteMemoryPool * feat: KPageTableBase/KPageTable new methods to read and write `ReadOnlySequence<byte>` * new: add IWritableBlock.Write(ulong, ReadOnlySequence<byte>) with default impl * perf: use GetReadOnlySequence() instead of GetSpan() * perf: make `Parcel` IDisposable, use `ByteMemoryPool` for internal allocation, and make Parcel consumers dispose of it * remove comment about copySize * remove unnecessary Clear()
This commit is contained in:
parent
7070cf6ae5
commit
216026c096
9 changed files with 98 additions and 25 deletions
|
@ -570,7 +570,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
}
|
||||
else
|
||||
{
|
||||
serverProcess.CpuMemory.Write(copyDst, clientProcess.CpuMemory.GetSpan(copySrc, (int)copySize));
|
||||
serverProcess.CpuMemory.Write(copyDst, clientProcess.CpuMemory.GetReadOnlySequence(copySrc, (int)copySize));
|
||||
}
|
||||
|
||||
if (clientResult != Result.Success)
|
||||
|
@ -858,7 +858,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
}
|
||||
else
|
||||
{
|
||||
clientProcess.CpuMemory.Write(copyDst, serverProcess.CpuMemory.GetSpan(copySrc, (int)copySize));
|
||||
clientProcess.CpuMemory.Write(copyDst, serverProcess.CpuMemory.GetReadOnlySequence(copySrc, (int)copySize));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ using Ryujinx.Horizon.Common;
|
|||
using Ryujinx.Memory;
|
||||
using Ryujinx.Memory.Range;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
|
@ -34,6 +35,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override ReadOnlySequence<byte> GetReadOnlySequence(ulong va, int size)
|
||||
{
|
||||
return _cpuMemory.GetReadOnlySequence(va, size);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override ReadOnlySpan<byte> GetSpan(ulong va, int size)
|
||||
{
|
||||
|
@ -247,6 +254,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
_cpuMemory.SignalMemoryTracking(va, size, write);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Write(ulong va, ReadOnlySequence<byte> data)
|
||||
{
|
||||
_cpuMemory.Write(va, data);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Write(ulong va, ReadOnlySpan<byte> data)
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@ using Ryujinx.Horizon.Common;
|
|||
using Ryujinx.Memory;
|
||||
using Ryujinx.Memory.Range;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
|
@ -1568,7 +1569,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
|
||||
while (size > 0)
|
||||
{
|
||||
ulong copySize = 0x100000; // Copy chunck size. Any value will do, moderate sizes are recommended.
|
||||
ulong copySize = int.MaxValue;
|
||||
|
||||
if (copySize > size)
|
||||
{
|
||||
|
@ -1577,11 +1578,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
|
||||
if (toServer)
|
||||
{
|
||||
currentProcess.CpuMemory.Write(serverAddress, GetSpan(clientAddress, (int)copySize));
|
||||
currentProcess.CpuMemory.Write(serverAddress, GetReadOnlySequence(clientAddress, (int)copySize));
|
||||
}
|
||||
else
|
||||
{
|
||||
Write(clientAddress, currentProcess.CpuMemory.GetSpan(serverAddress, (int)copySize));
|
||||
Write(clientAddress, currentProcess.CpuMemory.GetReadOnlySequence(serverAddress, (int)copySize));
|
||||
}
|
||||
|
||||
serverAddress += copySize;
|
||||
|
@ -1911,9 +1912,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
Context.Memory.Fill(GetDramAddressFromPa(dstFirstPagePa), unusedSizeBefore, (byte)_ipcFillValue);
|
||||
|
||||
ulong copySize = addressRounded <= endAddr ? addressRounded - address : size;
|
||||
var data = srcPageTable.GetSpan(addressTruncated + unusedSizeBefore, (int)copySize);
|
||||
var data = srcPageTable.GetReadOnlySequence(addressTruncated + unusedSizeBefore, (int)copySize);
|
||||
|
||||
Context.Memory.Write(GetDramAddressFromPa(dstFirstPagePa + unusedSizeBefore), data);
|
||||
((IWritableBlock)Context.Memory).Write(GetDramAddressFromPa(dstFirstPagePa + unusedSizeBefore), data);
|
||||
|
||||
firstPageFillAddress += unusedSizeBefore + copySize;
|
||||
|
||||
|
@ -1977,9 +1978,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
if (send)
|
||||
{
|
||||
ulong copySize = endAddr - endAddrTruncated;
|
||||
var data = srcPageTable.GetSpan(endAddrTruncated, (int)copySize);
|
||||
var data = srcPageTable.GetReadOnlySequence(endAddrTruncated, (int)copySize);
|
||||
|
||||
Context.Memory.Write(GetDramAddressFromPa(dstLastPagePa), data);
|
||||
((IWritableBlock)Context.Memory).Write(GetDramAddressFromPa(dstLastPagePa), data);
|
||||
|
||||
lastPageFillAddr += copySize;
|
||||
|
||||
|
@ -2943,6 +2944,18 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
/// <param name="pageList">Page list where the ranges will be added</param>
|
||||
protected abstract void GetPhysicalRegions(ulong va, ulong size, KPageList pageList);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a read-only sequence of data from CPU mapped memory.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Allows reading non-contiguous memory without first copying it to a newly allocated single contiguous block.
|
||||
/// </remarks>
|
||||
/// <param name="va">Virtual address of the data</param>
|
||||
/// <param name="size">Size of the data</param>
|
||||
/// <returns>A read-only sequence of the data</returns>
|
||||
/// <exception cref="Ryujinx.Memory.InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception>
|
||||
protected abstract ReadOnlySequence<byte> GetReadOnlySequence(ulong va, int size);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a read-only span of data from CPU mapped memory.
|
||||
/// </summary>
|
||||
|
@ -2952,7 +2965,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
/// </remarks>
|
||||
/// <param name="va">Virtual address of the data</param>
|
||||
/// <param name="size">Size of the data</param>
|
||||
/// <param name="tracked">True if read tracking is triggered on the span</param>
|
||||
/// <returns>A read-only span of the data</returns>
|
||||
/// <exception cref="Ryujinx.Memory.InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception>
|
||||
protected abstract ReadOnlySpan<byte> GetSpan(ulong va, int size);
|
||||
|
@ -3060,6 +3072,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
/// <param name="size">Size of the region</param>
|
||||
protected abstract void SignalMemoryTracking(ulong va, ulong size, bool write);
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to CPU mapped memory, with write tracking.
|
||||
/// </summary>
|
||||
/// <param name="va">Virtual address to write the data into</param>
|
||||
/// <param name="data">Data to be written</param>
|
||||
/// <exception cref="Ryujinx.Memory.InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception>
|
||||
protected abstract void Write(ulong va, ReadOnlySequence<byte> data);
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to CPU mapped memory, with write tracking.
|
||||
/// </summary>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue