Mod: Do LayeredFs loading Parallel to improve speed (#6180)

* Mod: Do LayeredFs loading Parallel to improve speed

This fixes and superseed #5672 due to inactivity, nothing more.
(See original PR for description)

Testing are welcome.

Close #5661

* Addresses gdkchan's feedback

* commit to test mako change

* Revert "commit to test mako change"

This reverts commit 8b0caa8a21db298db3dfcbe5b7e9029c4f066c46.
This commit is contained in:
Ac_K 2024-01-29 16:32:34 +01:00 committed by GitHub
parent 30bdc4544e
commit 7795b662a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 72 additions and 6 deletions

View File

@ -18,6 +18,7 @@ using System.Collections.Specialized;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using LazyFile = Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy.LazyFile;
using Path = System.IO.Path; using Path = System.IO.Path;
namespace Ryujinx.HLE.HOS namespace Ryujinx.HLE.HOS
@ -512,7 +513,7 @@ namespace Ryujinx.HLE.HOS
using (IFileSystem fs = new LocalFileSystem(mod.Path.FullName)) using (IFileSystem fs = new LocalFileSystem(mod.Path.FullName))
{ {
AddFiles(fs, mod.Name, fileSet, builder); AddFiles(fs, mod.Name, mod.Path.FullName, fileSet, builder);
} }
count++; count++;
} }
@ -528,7 +529,7 @@ namespace Ryujinx.HLE.HOS
Logger.Info?.Print(LogClass.ModLoader, $"Found 'romfs.bin' for Application {applicationId:X16}"); Logger.Info?.Print(LogClass.ModLoader, $"Found 'romfs.bin' for Application {applicationId:X16}");
using (IFileSystem fs = new RomFsFileSystem(mod.Path.OpenRead().AsStorage())) using (IFileSystem fs = new RomFsFileSystem(mod.Path.OpenRead().AsStorage()))
{ {
AddFiles(fs, mod.Name, fileSet, builder); AddFiles(fs, mod.Name, mod.Path.FullName, fileSet, builder);
} }
count++; count++;
} }
@ -561,18 +562,18 @@ namespace Ryujinx.HLE.HOS
return newStorage; return newStorage;
} }
private static void AddFiles(IFileSystem fs, string modName, ISet<string> fileSet, RomFsBuilder builder) private static void AddFiles(IFileSystem fs, string modName, string rootPath, ISet<string> fileSet, RomFsBuilder builder)
{ {
foreach (var entry in fs.EnumerateEntries() foreach (var entry in fs.EnumerateEntries()
.AsParallel()
.Where(f => f.Type == DirectoryEntryType.File) .Where(f => f.Type == DirectoryEntryType.File)
.OrderBy(f => f.FullPath, StringComparer.Ordinal)) .OrderBy(f => f.FullPath, StringComparer.Ordinal))
{ {
using var file = new UniqueRef<IFile>(); var file = new LazyFile(entry.FullPath, rootPath, fs);
fs.OpenFile(ref file.Ref, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
if (fileSet.Add(entry.FullPath)) if (fileSet.Add(entry.FullPath))
{ {
builder.AddFile(entry.FullPath, file.Release()); builder.AddFile(entry.FullPath, file);
} }
else else
{ {

View File

@ -0,0 +1,65 @@
using LibHac;
using LibHac.Common;
using LibHac.Fs;
using System;
using System.IO;
namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
{
class LazyFile : LibHac.Fs.Fsa.IFile
{
private readonly LibHac.Fs.Fsa.IFileSystem _fs;
private readonly string _filePath;
private readonly UniqueRef<LibHac.Fs.Fsa.IFile> _fileReference = new();
private readonly FileInfo _fileInfo;
public LazyFile(string filePath, string prefix, LibHac.Fs.Fsa.IFileSystem fs)
{
_fs = fs;
_filePath = filePath;
_fileInfo = new FileInfo(prefix + "/" + filePath);
}
private void PrepareFile()
{
if (_fileReference.Get == null)
{
_fs.OpenFile(ref _fileReference.Ref, _filePath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
}
}
protected override Result DoRead(out long bytesRead, long offset, Span<byte> destination, in ReadOption option)
{
PrepareFile();
return _fileReference.Get!.Read(out bytesRead, offset, destination);
}
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source, in WriteOption option)
{
throw new NotSupportedException();
}
protected override Result DoFlush()
{
throw new NotSupportedException();
}
protected override Result DoSetSize(long size)
{
throw new NotSupportedException();
}
protected override Result DoGetSize(out long size)
{
size = _fileInfo.Length;
return Result.Success;
}
protected override Result DoOperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size, ReadOnlySpan<byte> inBuffer)
{
throw new NotSupportedException();
}
}
}